Qt 多线程之QtConcurrent::map(处理序列容器)

1 篇文章 0 订阅

QtConcurrent::map()、QtConcurrent::mapped() 和 QtConcurrent::mappedReduced() 函数对一个序列中(例如:QList、QVector)的项目并行地进行计算。

1、map函数

map函数的功能是在其他线程运行指定的函数,map函数有两个参数

第一个是集合

第二个参数是一个函数。它的作用就是同时用第二个参数来计算第一个参数中的每一个元素,且结果直接覆盖到元素中,如果是成员函数,那要静态成员函数才能运行

//静态函数
void Widget::Func(QPushButton * & btn)
{
    QTime time = QTime::currentTime();
    qsrand(time.msec() + time.second()*1000);
    btn->setText(QString("按钮_%1").arg(qrand() % 20));
    qDebug()<<"thread ID"<<QThread::currentThreadId();
}
  
void Widget::on_pushButton_clicked()
{
     QList<QPushButton*> list = this->findChildren<QPushButton*>();
     QFuture<void> f = QtConcurrent::map(list,&Widget::Func); //map函数 不能运行非静态成员函数
     f.waitForFinished();
}

结果:

2、mapped函数

mapped函数的作用和map类似,只是把计算结果放到了新的容器中

例子1:

int func2(int a)
{
     return a + 1;
}

void Widget::on_pushButton_clicked()
{
     QList<int> alist;
     alist<<1<<3<<5<<7<<9;
  
     QFuture<int> f = QtConcurrent::mapped(alist,func2); //QFuture的类型为int
     f.waitForFinished();
     qDebug()<<"alist"<<alist;
     QList<int> newlist = f.results();
     qDebug()<<"newlist"<<newlist;
}

结果:

例子2:

 QPushButton* Widget::Func2(QPushButton * btn)
 {
    QThread::msleep(200);
    QTime time = QTime::currentTime();
    qsrand(time.msec() + time.second()*1000);
    btn->setText(QString("按钮_%1").arg(qrand() % 20));
    qDebug()<<"thread ID"<<QThread::currentThreadId();
     return btn;
 }
  
 void Widget::on_pushButton_clicked()
 {
     QList<QPushButton*> list = this->findChildren<QPushButton*>();
     QFuture<QPushButton*> f2 = QtConcurrent::mapped(list,&Widget::Func2);
     f2.waitForFinished();
 }

结果:

关于mapped,官方有个:Image Scaling Example例子,通过一次性加载多张图片,分别转成100*100的缩略图显示在界面来演示mapped的使用。

 //图片转换成100*100的图片
 QImage scale(const QString &imageFileName)
 {
     QImage image(imageFileName);
     QThread::msleep(500);
    return image.scaled(QSize(imageSize, imageSize), Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
 }
 
 QFutureWatcher imageScaling = new QFutureWatcher<QImage>(this);
 connect(imageScaling, &QFutureWatcherBase::resultReadyAt, this, &Images::showImage); 
 connect(imageScaling, &QFutureWatcherBase::finished, this, &Images::finished);
  
 QStringList files;//图片地址
 imageScaling->setFuture(QtConcurrent::mapped(files, scale));
  
 connect(pauseButton, &QAbstractButton::clicked, imageScaling, 
 &QFutureWatcherBase::togglePaused);//暂停/恢复操作

QFutureWatcherBase::togglePaused 暂停/继续操作

QFutureWatcherBase::resultReadyAt 读取到一个结果

可以用这些信号来设置处理的进度条

用这些信号设置进度条官方正好有个叫:QtConcurrent Progress Dialog Example的简单例子:
 

 void spin(int &iteration)
 {
     volatile int v = 0;
     for (int j = 0; j < 400000000; ++j)
         ++v;
     qDebug() << "处理值" << iteration << "的线程:" << QThread::currentThreadId();
 }
  
int main(int argc, char **argv)
 {
     QApplication app(argc, argv);
  
     QVector<int> vector;
     for (int i = 0; i < 20; ++i)
         vector.append(i);
  
     QProgressDialog dialog;
     dialog.setLabelText(QString("正在使用 %1 个线程...").arg(QThread::idealThreadCount()));
  
     QFutureWatcher<void> futureWatcher;
     QObject::connect(&futureWatcher, &QFutureWatcherBase::finished, &dialog, &QProgressDialog::reset);
     QObject::connect(&dialog, &QProgressDialog::canceled, &futureWatcher, &QFutureWatcherBase::cancel);
     QObject::connect(&futureWatcher, &QFutureWatcherBase::progressRangeChanged, &dialog, &QProgressDialog::setRange);
     QObject::connect(&futureWatcher, &QFutureWatcherBase::progressValueChanged, &dialog, &QProgressDialog::setValue);
  
     futureWatcher.setFuture(QtConcurrent::map(vector, spin));
     dialog.exec();
     futureWatcher.waitForFinished();
     qDebug() << "Canceled?" << futureWatcher.future().isCanceled();
 }

3、mappedReduced函数

mappedReduced函数比mapped多一个参数,这个参数也是个函数。作用就是将mapped出来的结果再计算最终得出一个值。

 int func3(int a)
 {
     return a + 1;
 }
  
 void sum(int& result, const int& b)
 {
     result += b;
 }
  
 void Widget::on_pushButton_clicked()
 {
     QList<int> alist;
     alist<<1<<3<<5<<7<<9;
  
     QFuture<int> result = QtConcurrent::mappedReduced(alist,func3,sum);
     result.waitForFinished();
     qDebug()<<result.result();
 }

 alist中的一个值执行完func3马上执行sum,而不是alist中所有之都执行完才执行sum。

结果:

 

关于mappedReduced,官方的demo中有个叫做QtConcurrent Word Count Example的例子通过单线程/多线程统计文件夹中单词个数来演示mappedReduced的使用。

  //遍历文件夹,返回文件夹内所有文件名
 QStringList findFiles(const QString &startDir, QStringList filters)
  {
      QStringList names;
      QDir dir(startDir);
   
      foreach (QString file, dir.entryList(filters, QDir::Files))
          names += startDir + "/" + file;
   
     foreach (QString subdir, dir.entryList(QDir::AllDirs | QDir::NoDotAndDotDot))
         names += findFiles(startDir + "/" + subdir, filters);
     return names;
 }
  
 //单线程计算此文件列表中每个文件的单词个数:<文件名,单词个数>
 QMap<QString, int> singleThreadedWordCount(QStringList & files)
 {
     QMap<QString, int> wordCount;
     QString word;
     foreach (QString file, files)
     {
         QFile f(file);
         f.open(QIODevice::ReadOnly);
         QTextStream textStream(&f);
         while (textStream.atEnd() == false)
             foreach(word, textStream.readLine().split(" "))
                 wordCount[word] += 1;
     }
     return wordCount;
 }
  
 //计算一个文件中单词数
 QMap<QString, int> countWords(const QString &file)
 {
     QFile f(file);
     f.open(QIODevice::ReadOnly);
     QTextStream textStream(&f);
     QMap<QString, int> wordCount;
  
     while (textStream.atEnd() == false)
         foreach (QString word, textStream.readLine().split(" "))
             wordCount[word] += 1;
  
     return wordCount;
 }
  
 void reduce(QMap<QString, int> &result, const QMap<QString, int> &w)
 {
     QMapIterator<QString, int> it(w);
     while (it.hasNext())
     {
         it.next();
         result[it.key()] += it.value();
     }
 }
  int main(int argc, char** argv)
 {
     QApplication app(argc, argv);
     qDebug() << "正在查找文件...";
     QStringList files = findFiles("../../",
                                   QStringList() << "*.cpp" << "*.h");//查找此格式的文件
     QTime time;
     time.start();
     QMap<QString, int> total = singleThreadedWordCount(files);
  
     int singleThreadTime = 0;
     {
         QTime time;
         time.start();
         QMap<QString, int> total = singleThreadedWordCount(files);
         singleThreadTime = time.elapsed();
         qDebug() << "单线程统计这些文件单词数所需时间:" << singleThreadTime;
     }
  
     int mapReduceTime = 0;
     {
         QTime time;
         time.start();
         QMap<QString, int> total = mappedReduced(files, countWords, reduce);
         mapReduceTime = time.elapsed();
         qDebug() << "MapReduce" << mapReduceTime;
     }
     qDebug() << "速度提升倍数:" << ((double)singleThreadTime - (double)mapReduceTime) / (double)mapReduceTime + 1;
 }
QMap<QString, int> total = mappedReduced(files, countWords, reduce);

这句在多线程里对文件列表中的每个文件执行统计单词操作(执行countWords),然后把统计结果存到QMap中(执行reduce)

打印reduce()中的result的地址可以发现result一直是同一个,猜测:这个QMap<QString, int> &result是mappedReduced申请的,执行reduce时候把数据都保存到这个result里,执行完mappedReduced了就返回值

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值