QtConcurrent框架是Qt中的一个高级多线程编程框架,可以方便地实现并行计算和任务分发。它有以下优势:
-
简单易用:QtConcurrent提供了一组简单易用的函数,允许开发者无需关注线程的创建、管理和同步等细节,只需要专注于业务逻辑的实现。
-
高效可靠:QtConcurrent采用了现代化的并行编程技术,包括线程池、Futures和Promises等,可以充分利用多核CPU资源,提高程序的运行效率和性能。
-
跨平台支持:QtConcurrent框架可以在多种操作系统平台上运行,包括Windows、Linux和macOS等。
使用QtConcurrent框架时,要注意以下细节:
-
函数需符合一定规范:使用QtConcurrent::run()函数时,被调用的函数必须是静态成员函数、全局函数或lambda表达式,并且参数列表不能包含QObject*类型的对象。
-
使用QFuture类获取执行结果:QtConcurrent::run()函数返回一个QFuture对象,可以通过QFuture的相关接口来获取执行结果。
-
避免共享数据:在多线程环境下,需要避免不同线程之间的数据竞争,因此应该尽量避免共享数据。如果确实需要共享数据,可以使用Qt提供的同步机制来进行线程同步和资源共享。
-
使用适当数量的线程:在创建线程池时,应该考虑任务的类型、数量和复杂度等因素,选择适当数量的线程来保证程序的性能和稳定性。
QtConcurrent的线程池会根据系统的硬件和可用资源动态地管理线程数量,以提供最佳的性能和稳定性。它会根据任务的类型、数量和复杂度等因素来动态分配和调整线程的数量,避免过多或过少的线程导致的资源浪费或性能下降。
通过QtConcurrent提供的函数,例如
QtConcurrent::run()
和QtConcurrent::mapped()
,可以将任务提交给线程池进行执行。QtConcurrent会自动选择合适的线程来运行这些任务,并确保线程安全和数据共享的正确性。
总之,QtConcurrent框架为开发者提供了一种简单、高效、可靠的多线程编程方式,可以大大加速程序的运行和提高用户体验。但是,在使用时需要注意避免线程安全问题,合理分配线程资源,以及遵循Qt的编程规范和最佳实践。
代码示例:
#include <QtCore>
#include <QtConcurrent>
int main(int argc, char *argv[])
{
QCoreApplication app(argc, argv);
// 定义一个QStringList对象
QStringList list;
list << "hello" << "world" << "good" << "morning";
// 使用mapped函数将每个字符串转换为大写形式
QFuture<QString> future = QtConcurrent::mapped(list, [](const QString& str) {
return str.toUpper();
});
// 等待任务执行完成
future.waitForFinished();
// 输出结果
foreach (const QString& str, future.results()) {
qDebug() << str;
}
return app.exec();
}
提到这里就必须提一提多个函数的使用和示例:
run()函数
#include <QCoreApplication>
#include <QtConcurrent>
#include <QDebug>
void function()
{
qDebug() << "Hello world";
}
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
QtConcurrent::run(function); //调用 run() 函数就可以在单独线程里运行
return a.exec();
}
直接在函数名后面跟上参数可以直接传递;
extern void aFunction(int arg1, double arg2, const QString &string);
int a = 1;
double b = 2;
QString string = "hello";
QtConcurrent::run(aFunction, a, b, string);
通过QFuture获取返回值
extern QString function();
QFuturen<QString> future = QtConcurrent::run(function);
QString result = future.result();
run还可以接收成员指针:
QByteArray bytearray = "hello,world";
QFuture<QList<QByteArray> > future = QtConcurrent::run(bytearray, &QByteArray::split, ',');
QList<QByteArray> result = future.result();
也可以接收匿名函数的lamda表达式:
QFuture<void> future = QtConcurrent::run([=](){..Code..});
map函数:
map 相关的函数主要应用场景是在单独的线程里对容器中的每一项进行操作。这些函数主要分为三类:
- QtConcurrent::map():直接操作容器中的每一项。
- QtConcurrent::mapped():操作容器中的每一项,将处理结果返回一个新的容器,原容器不变。
- QtConcurrent::mappedReduced():在 mapped() 的基础上将处理结果进一步传递给一个函数继续处理
QtConcurrent::map() 可以直接修改容器的每一项,处理函数必须是“U function(T &t)”的形式。因为是直接修改,所以 map() 函数不会返回任何 QFuture 结果,但仍然可以使用 QFuture 和 QFutureWatcher 来监视状态。
#include <QCoreApplic
ation>
#include <QtConcurrent>
#include <QDebug>
void function(int &num)
{
num = num * 10;
}
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
QList<int> list = {1,2,3,4,5};
QtConcurrent::map(list, function);
return a.exec();
}
QtConcurrent::mapped() 不直接修改容器的每一项,而是将处理后的结果返回一个新的容器,处理函数必须是“U function(const T &t)”的形式。
#include <QCoreApplication>
#include <QtConcurrent>
#include <QFutureIterator>
#include <QDebug>
int function(const int &num)
{
return num * 10;
}
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
QList<int> list = {1,2,3,4,5};
QFuture<int> future = QtConcurrent::mapped(list, function);
QFutureIterator<int> i(future);
return a.exec();
}
QtConcurrent::mappedReduced() 类似于 mapped(),区别在于将结果继续传递给一个新函数,并在新函数里再处理成一个单值。新函数必须是“V function(T &result,const U &intermediate)”的形式。
#include <QCoreApplication>
#include <QtConcurrent>
#include <QDebug>
int function(const int &num)
{
return num * 10;
}
void reducedFunction(int &result, const int &intermedia)
{
result += intermedia;
}
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
QList<int> list = {1,2,3,4,5};
QFuture<int> future = QtConcurrent::mappedReduced(list, function, reducedFunction);
qDebug() << result;
return a.exec();
}
必须要注意的是,上面都是单独开了一个线程所执行的。写自己的示例时,debug 的结果可能是容器中的元素并未改变,这是因为处理过程是异步的,它不是立即返回。QtConcurrent相关的函数都有 Blocking 的写法,就是等待结果可用时才会继续运行下去。
- QtConcurrent::blockingMap
- QtConcurrent::blockingMapped
- QtConcurrent::blockingMappedReduced
- QtConcurrent::blockingfilter
- QtConcurrent::blockingfiltered
- QtConcurrent::blockingfilteredReduced