简介
QtConcurrent
命名空间提供了高级API,可以在不使用低级别线程原语(如互斥锁,读写锁,等待条件或信号量)的情况下编写多线程程序。 使用QtConcurrent
编写的程序会根据可用的处理器内核数自动调整使用的线程数。 这意味着今后编写的应用程序将在未来部署到多核系统时可以充分利用更多的处理器内核。
依赖
如要使用QtConcurrent
,需要在Qt工程中加入concurrent
模块,在qmake
中写入如下:
QT += concurrent
之后便可以在QtConcurrent
命名空间使用。
基础梳理
QtConcurrent
包含用于并行列表处理的函数式编程风格API,包括为共享内存(非分布式)系统所实现的MapReduce
和FilterReduce
以及用于在GUI应用程序中管理异步计算的类:
- Concurrent
Map
和Map-Reduce
QtConcurrent::map()
将函数应用于容器中的每个项目,并就地修改项目。QtConcurrent::mapped()
就像map()
,不同之处在于它返回一个只包含修改内容的新容器。QtConcurrent::mappedReduced()
类似于mapped()
,除了修改后的结果被减少或组合成单个结果。
- Concurrent
Filter
和Filter-Reduce
QtConcurrent::filter()
根据过滤函数从容器中删除所有满足要求的项目。QtConcurrent::filtered()
与filter()
类似,只不过它返回一个新的容器和过滤后的结果。QtConcurrent::filteredReduced()
与filtered()
类似,只是过滤的结果减少或组合成单个结果。
- Concurrent 运行
QtConcurrent::run()
:在另一个线程中直接运行一个现有函数。
QFuture
:代表异步计算的结果。QFutureIterator
:QFuture
所提供结果的迭代器。QFutureWatcher
:允许使用信号和插槽来监视QFuture
。QFutureSynchronizer
:是一个便利的类,可以自动同步几个QFutures
。
Qt Concurrent
支持几种与STL兼容的容器和迭代器类型,但最适用于具有随机访问迭代器的Qt容器,如QList
或QVector
。 map
和filter
函数都接受容器和begin
/ end
迭代器。
STL 迭代器支持一览
迭代类型 | 示例类 | 支持状态 |
---|---|---|
Input Iterator | 不支持 | |
Output Iterator | 不支持 | |
Forward Iterator | std::slist | 支持 |
Bidirectional Iterator | QLinkedList, std::list | 支持 |
Random Access Iterator | QList, QVector, std::vector | 支持并推荐 |
在Qt Concurrent
迭代大量轻量级items的情况下,随机访问迭代器可以更快,因为它们允许跳到容器中的任何点。 另外,使用随机访问迭代器允许Qt Concurrent
通过QFuture::progressValue()
和QFutureWatcher::progressValueChanged()
提供进度信息。
诸如mapped()
和filtered()
之类的非原地修改函数在调用时会创建容器的副本。 如果您正在使用STL容器,则此复制操作可能需要一些时间,在这种情况下,我们建议您改为指定容器的begin
和end
迭代器。
示例
接下来让我们看一个简单的例子
#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();
}