Qt-QtConcurrent的使用

QtConcurren导读

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基本使用

  1. QtConcurrent的常用方法QtConcurrent::run()QtConcurrent::map()QtConcurrent::filter()。map和filter还有其衍生的方法,例如还有mapped()mappedReduced()filtered()filteredReduced。下面通过使用这几个方法来了解QtConcurrent的使用方法。
  2. run方法
    run方法是通过另开一个线程来执行用户指定的函数,需要注意的是这个线程是在线程池中获取的,也就是说这个线程是不需要手动释放的,运行完指定的函数线程会自动释放。下面通过几个示例说明一下怎么使用。
  • 调用用户自定义的函数
//自定义函数
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"
**/
  • 调用qt类库中的函数
	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")
  1. map函数及其衍生函数
  • map 函数用于需要更改原容器中数据的使用场景,对容器中的每个项目都调用一次函数,且每次调用都是单独的一个线程。这个没有返回新容器,所以不能通过future获取结果。线程也来自线程池,和run方法类似
 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")
  • mapped方法
    mapped 函数用于不改变原容器数据,返回处理新容器结果的使用场景,与map类似,因为返回新容器,所以能通过future获取结果

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")
  • mappedReduced()方法
    mappedReduced 用于mapped处理后的结果还需要进行处理的使用场景。
 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"))
  1. filter函数及其衍生函数
    filter函数与map函数类似,其衍生函数也与map的衍生函数类似,只是函数用于过滤。这里通过一个例子全部展示。
 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,顾名思义,一般用于对一批数据的过滤操作。
至此,基本使用就是这些,更细致的操作还请参考帮助文档~~~

你可能感兴趣的:(Qt与QML,qt5,多线程)