Qt Concurrent

简介


QtConcurrent命名空间提供了高级API,可以在不使用低级别线程原语(如互斥锁,读写锁,等待条件或信号量)的情况下编写多线程程序。 使用QtConcurrent编写的程序会根据可用的处理器内核数自动调整使用的线程数。 这意味着今后编写的应用程序将在未来部署到多核系统时可以充分利用更多的处理器内核。

依赖


如要使用QtConcurrent,需要在Qt工程中加入concurrent模块,在qmake中写入如下:

QT += concurrent

之后便可以在QtConcurrent命名空间使用。


基础梳理

QtConcurrent包含用于并行列表处理的函数式编程风格API,包括为共享内存(非分布式)系统所实现的MapReduceFilterReduce以及用于在GUI应用程序中管理异步计算的类:

  • Concurrent MapMap-Reduce
    • QtConcurrent::map()将函数应用于容器中的每个项目,并就地修改项目。
    • QtConcurrent::mapped()就像map(),不同之处在于它返回一个只包含修改内容的新容器。
    • QtConcurrent::mappedReduced()类似于mapped(),除了修改后的结果被减少或组合成单个结果。
  • Concurrent FilterFilter-Reduce
    • QtConcurrent::filter()根据过滤函数从容器中删除所有满足要求的项目。
    • QtConcurrent::filtered()filter()类似,只不过它返回一个新的容器和过滤后的结果。
    • QtConcurrent::filteredReduced()filtered()类似,只是过滤的结果减少或组合成单个结果。
  • Concurrent 运行
    • QtConcurrent::run():在另一个线程中直接运行一个现有函数。
  • QFuture:代表异步计算的结果。
  • QFutureIterator:QFuture所提供结果的迭代器。
  • QFutureWatcher:允许使用信号和插槽来监视QFuture
  • QFutureSynchronizer:是一个便利的类,可以自动同步几个QFutures

Qt Concurrent支持几种与STL兼容的容器和迭代器类型,但最适用于具有随机访问迭代器的Qt容器,如QListQVectormapfilter函数都接受容器和begin / end迭代器。

STL 迭代器支持一览


迭代类型示例类支持状态
Input Iterator不支持
Output Iterator不支持
Forward Iteratorstd::slist支持
Bidirectional IteratorQLinkedList, std::list支持
Random Access IteratorQList, QVector, std::vector支持并推荐

Qt Concurrent迭代大量轻量级items的情况下,随机访问迭代器可以更快,因为它们允许跳到容器中的任何点。 另外,使用随机访问迭代器允许Qt Concurrent通过QFuture::progressValue()QFutureWatcher::progressValueChanged()提供进度信息。

诸如mapped()filtered()之类的非原地修改函数在调用时会创建容器的副本。 如果您正在使用STL容器,则此复制操作可能需要一些时间,在这种情况下,我们建议您改为指定容器的beginend迭代器。

示例

接下来让我们看一个简单的例子

#include <QtWidgets>
  #include <QtConcurrent>
  #include <functional>
  using namespace QtConcurrent;

  int main(int argc, char **argv)
  {
      QApplication app(argc, argv);
      const int iterations = 20;

      // 准备好数据
      QVector<int> vector;
      for (int i = 0; i < iterations; ++i)
          vector.append(i);

      // 创建一个进度显示弹窗
      QProgressDialog dialog;
      dialog.setLabelText(QString("使用%1个线程处理").arg(QThread::idealThreadCount()));

      // 创建一个QFutureWatcher并且连接好信号与槽
      QFutureWatcher<void> futureWatcher;
      QObject::connect(&futureWatcher, &QFutureWatcher<void>::finished, &dialog, &QProgressDialog::reset);
      QObject::connect(&dialog, &QProgressDialog::canceled, &futureWatcher, &QFutureWatcher<void>::cancel);
      QObject::connect(&futureWatcher,  &QFutureWatcher<void>::progressRangeChanged, &dialog, &QProgressDialog::setRange);
      QObject::connect(&futureWatcher, &QFutureWatcher<void>::progressValueChanged,  &dialog, &QProgressDialog::setValue);

      // 我们模拟需要并行执行的程序
      std::function<void(int&)> spin = [](int &iteration) {
          const int work = 1000 * 1000 * 40;
          volatile int v = 0;
          for (int j = 0; j < work; ++j)
              ++v;

          qDebug() << "在线程:" << QThread::currentThreadId()<<"中的第"<<iteration<<"部分";
      };

      // 开始执行
      futureWatcher.setFuture(QtConcurrent::map(vector, spin));

      // 显示弹窗并开始时间循环
      dialog.exec();

      futureWatcher.waitForFinished();

      // 检查是否取消
      qDebug() << "Canceled?" << futureWatcher.future().isCanceled();
  }
  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值