Qt之Concurrent框架
簡述
QtConcurrent 命名空間提供了高級 API,使得可以在不使用低級線程原語(例如:互斥、讀寫鎖、等待條件或信號量)的情況下編寫多線程程序,使用 QtConcurrent 編寫的程序根據(jù)可用的處理器核心數(shù)自動調(diào)整所使用的線程數(shù)。這意味著,當(dāng)在未來部署多核系統(tǒng)時,現(xiàn)在編寫的應(yīng)用程序?qū)⒗^續(xù)適應(yīng)。
- 簡述
- 用法
- Qt Concurrent
- 單詞統(tǒng)計
- 更多參考
用法
在 C++ API changes 有關(guān)于 Qt Concurrent 的更改說明:
Qt Concurrent has been moved from Qt Core to its own module
意思是說,Qt Concurrent 已經(jīng)被從 Qt Core 中移到自己的模塊中了。所以,要鏈接到 Qt Concurrent 模塊,需要在 qmake 項目文件中添加:
QT += concurrent注意: QtConcurrent::Exception 類被重命名為 QException,并且 QtConcurrent::UnhandledException 類被重命名為 QUnhandledException,他們?nèi)匀晃挥?Qt Core 中。
Qt Concurrent
QtConcurrent 包含了函數(shù)式編程風(fēng)格 APIs 用于并行列表處理,包括用于共享內(nèi)存(非分布式)系統(tǒng)的 MapReduce 和 FilterReduce 實現(xiàn),以及用于管理 GUI 應(yīng)用程序異步計算的類:
Concurrent Map 和 Map-Reduce
- QtConcurrent::map():將一個函數(shù)應(yīng)用于一個容器中的每一項,就地修改 items。
- QtConcurrent::mapped():和 map() 類似,只是它返回一個包含修改內(nèi)容的新容器。
- QtConcurrent::mappedReduced():和 mapped() 類似,只是修改后的結(jié)果減少或組合成一個單一的結(jié)果。
Concurrent Filter 和 Filter-Reduce
- QtConcurrent::filter():從一個容器中刪除所有 items,基于一個 filter 函數(shù)的結(jié)果。
- QtConcurrent::filtered():和 filter() 類似,只是它返回一個包含過濾內(nèi)容的新容器。
- QtConcurrent::filteredReduced():和 filtered() 類似,只是過濾后的結(jié)果減少或組合成一個單一的結(jié)果。
Concurrent Run
- QtConcurrent::run():在另一個線程中運行一個函數(shù)。
QFuture:表示異步計算的結(jié)果
- QFutureIterator:允許通過 QFuture 遍歷可用的結(jié)果
- QFutureWatcher:允許使用信號槽來監(jiān)控一個 QFuture
- QFutureSynchronizer:是一個方便的類,用于一些 QFutures 的自動同步
Qt Concurrent 支持多種兼容 STL 的容器和迭代器類型,但是最好使用具有隨機訪問迭代器的 Qt 容器,例如:QList 或 QVector。map 和 filter 函數(shù)都接受容器和 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() 來提供進(jìn)度信息。
非就地修改的函數(shù)(例如:mapped() 和 filtered()),在調(diào)用時會創(chuàng)建容器的副本。如果正在使用的是 STL 容器,此復(fù)制操作可能需要一段時間,在這種情況下,建議為容器指定 begin 和 end 迭代器。
單詞統(tǒng)計
厲害了 Concurrent,來看一個單詞統(tǒng)計的示例:
#include <QList> #include <QMap> #include <QTextStream> #include <QString> #include <QStringList> #include <QDir> #include <QTime> #include <QApplication> #include <QDebug>#include <qtconcurrentmap.h>using namespace QtConcurrent;// 遞歸搜索文件 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; }typedef QMap<QString, int> WordCount;// 單線程單詞計數(shù)器函數(shù) WordCount singleThreadedWordCount(QStringList files) {WordCount wordCount;foreach (QString file, files) {QFile f(file);f.open(QIODevice::ReadOnly);QTextStream textStream(&f);while (textStream.atEnd() == false)foreach (const QString &word, textStream.readLine().split(' '))wordCount[word] += 1;}return wordCount; }// countWords 計算單個文件的單詞數(shù),該函數(shù)由多個線程并行調(diào)用,并且必須是線程安全的。 WordCount countWords(const QString &file) {QFile f(file);f.open(QIODevice::ReadOnly);QTextStream textStream(&f);WordCount wordCount;while (textStream.atEnd() == false)foreach (const QString &word, textStream.readLine().split(' '))wordCount[word] += 1;return wordCount; }// reduce 將 map 的結(jié)果添加到最終結(jié)果,該函數(shù)只能由一個線程一次調(diào)用。 void reduce(WordCount &result, const WordCount &w) {QMapIterator<QString, int> i(w);while (i.hasNext()) {i.next();result[i.key()] += i.value();} }int main(int argc, char** argv) {QApplication app(argc, argv);qDebug() << "finding files...";QStringList files = findFiles("../../", QStringList() << "*.cpp" << "*.h");qDebug() << files.count() << "files";int singleThreadTime = 0;{QTime time;time.start();// 單線程統(tǒng)計,與 mapreduce 機制實現(xiàn)的作對比WordCount total = singleThreadedWordCount(files);singleThreadTime = time.elapsed();// 打印出所耗費的時間qDebug() << "single thread" << singleThreadTime;}int mapReduceTime = 0;{QTime time;time.start();// mappedReduced 方式進(jìn)行統(tǒng)計WordCount total = mappedReduced(files, countWords, reduce);mapReduceTime = time.elapsed();qDebug() << "MapReduce" << mapReduceTime;}// 輸出 mappedReduced 方式比單線程處理方式要快的倍數(shù)qDebug() << "MapReduce speedup x" << ((double)singleThreadTime - (double)mapReduceTime) / (double)mapReduceTime + 1; }輸出如下:
finding files…
2185 files
single thread 5221
MapReduce 2256
MapReduce speedup x 2.31427
可以看出,共查找了 2185 個文件,單線程使用了 5221 毫秒,MapReduce 方式使用了 2256 毫秒,比單線程要快 2.31427 倍。經(jīng)過反復(fù)嘗試,基本都在 2 倍以上。
更多參考
- Qt之Concurrent Map和Map-Reduce
- Qt之Concurrent Filter和Filter-Reduce
- Qt之Concurrent Run
- Qt之QFuture
- Qt之QFutureWatcher
轉(zhuǎn)載于:https://www.cnblogs.com/new0801/p/6146553.html
總結(jié)
以上是生活随笔為你收集整理的Qt之Concurrent框架的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 2021年机修钳工(中级)及机修钳工(中
- 下一篇: jfinal 和bjui 常用前后交互方