QtConcurrent提供了编写多线程程序的高级api,也即不使用低级线程原语,而其他实现多线程的方式,例如子类化QThread、QObject::moveToThread()、子类化QRunnable对于共享数据的保护都要使用低级线程原语,这无疑是要非常小心的。
此外,根据Qt文档的描述:Programs written with QtConcurrent automatically adjust the number of threads used according to the number of processor cores available. This means that applications written today will continue to scale when deployed on multi-core systems in the future.
,也就是说QtConcurrent可以根据机器的cpu自动调整线程数,以至于部署在其他机器上不用担心这方面的问题。
注:低级线程原语指的是:mutexes(互斥锁), read-write locks(读写锁), wait conditions(等待条件), or semaphores(信号量)
QtConcurrent::run()
、QtConcurrent::map()
、QtConcurrent::filter()
。map和filter还有其衍生的方法,例如还有mapped()
、mappedReduced()
、filtered()
、filteredReduced
。下面通过使用这几个方法来了解QtConcurrent的使用方法。//自定义函数
QString hello(QString name,QString name1,QString name2,QString name3){
qDebug() << "hello" <<name << "from" <<QThread::currentThread();
for(int i=0; i<3; i++){
QThread::sleep(1);
qDebug("[%s] i = %d",name.data(),i);
}
return name+name1+name2+name3;
}
run函数在线程中调用自定义的函数,后面可以跟函数的参数(可选),QFuture能够获取到函数执行的返回值,returnType必须和函数的返回类型一致
QFuture<QString> f1 = QtConcurrent::run(hello,QString("Alice"),QString("Alice"),QString("Alice"),QString("Alice"));
QFuture<QString> f2 = QtConcurrent::run(hello,QString("Bob"),QString("Bob"),QString("Bob"),QString("Bob"));
//QFuture::result()获取单个返回值
qDebug() << f1.result();
qDebug() << f2.result();
//等待结束释放
f1.waitForFinished();
f2.waitForFinished();
/**
输出:
hello "Bob" from QThreadPoolThread(0x6000018359b0, name = "Thread (pooled)")
hello "Alice" from QThreadPoolThread(0x600001835920, name = "Thread (pooled)")
[B] i = 0
[A] i = 0
[B] i = 1
[A] i = 1
[B] i = 2
[A] i = 2
"AliceAliceAliceAlice"
"BobBobBobBob"
**/
QByteArray bytearray = "h,ell,o wo,r,ld";
//调用qt类中的函数
QFuture<QList<QByteArray> > future = QtConcurrent::run(&QByteArray::split,bytearray,',');
qDebug() << future.result();
future.waitForFinished();
//输出:QList("h", "ell", "o wo", "r", "ld")
void toUpperMap(QString &str)
{
str = str.toUpper();
}
QStringList strWords;
strWords << "Apple" << "Banana" << "cow" << "dog" << "Egg";
//第一个参数是原容器,第二参数是每个项目需要调用的方法
auto future = QtConcurrent::map(strWords,toUpperMap);
future.waitForFinished();
qDebug() << strWords;
//输出:QList("APPLE", "BANANA", "COW", "DOG", "EGG")
QString toUperrMapped(const QString &str){
return str.toUpper();
}
QStringList oldStr;
oldStr << "Apple" << "Banana" << "cow" << "dog" << "Egg";
auto future = QtConcurrent::mapped(oldStr,toUperrMapped);
future.waitForFinished();
qDebug() << future.results();//results()返回全部数据,这里如果调用result()只会返回一个数据,即APPLE。
//输出:QList("APPLE", "BANANA", "COW", "DOG", "EGG")
QString toUperrMappedReduced(const QString &str){
return str.toUpper();
}
//进一步处理的函数
void reduceFun(QList<QString> &dictionary,const QString &string){
dictionary.push_back(QString("result:")+string);
}
QStringList oldStrReduced;
oldStrReduced << "Apple" << "Banana" << "cow" << "dog" << "Egg";
//最后一个参数是为了保证调用的顺序与输出的顺序一致,否则输出的结果顺序是不确定的,因为每个项目都是单独的一个线程处理,所以输出结果不一样。
auto future = QtConcurrent::mappedReduced(oldStrReduced,toUperrMappedReduced,reduceFun,QtConcurrent::OrderedReduce);
future.waitForFinished();
qDebug() << future.results()
//输出:QList(QList("result:APPLE", "result:BANANA", "result:COW", "result:DOG", "result:EGG"))
void reduceFun(QList<QString> &dictionary,const QString &string){
dictionary.push_back(QString("result:")+string);
}
bool fiter (QString string){
if(string.length()>3){ //只要长度大于3的字符串
return true;
}else return false;
}
QStringList oldStrfilter;
oldStrfilter << "Apple" << "Banana" << "cow" << "dog" << "Egg";
auto future1 = QtConcurrent::filter(oldStrfilter,fiter);
//filtered函数与mapped函数类似,只是函数用于过滤
auto future2 = QtConcurrent::filtered(oldStrfilter,fiter);
//filteredReduced函数与mappedReduced函数类似,只是函数用于过滤
auto future3 = QtConcurrent::filteredReduced(oldStrfilter,fiter,reduceFun);
future1.waitForFinished();
future2.waitForFinished();
future3.waitForFinished();
qDebug() << oldStrfilter;
qDebug() << future2.results();
qDebug() << future3.results();
/**
输出:
QList("Apple", "Banana")
QList("Apple", "Banana")
QList(QList("result:Apple", "result:Banana"))
**/
QtConcurrent::run
,在线程池内起一个线程来执行一个函数。
QtConcurrent::map
, 用于并行处理一批数据的场景。
QtConcurrent::filter
,顾名思义,一般用于对一批数据的过滤操作。
至此,基本使用就是这些,更细致的操作还请参考帮助文档~~~