QT 並行運算高階API QtConcurrent
Qt Concurrent模組擴充套件了Qt Core模組中的基本執行緒支援,簡化了可以在所有可用的CPU核心上並行執行的程式碼開發。
一些常用API:
- Concurrent Map 和 Map-Reduce
QtConcurrent::map():將一個函式應用於一個容器中的每一項,就地修改 items。
QtConcurrent::mapped():和 map() 類似,只是它返回一個包含修改內容的新容器。
QtConcurrent::mappedReduced():和 mapped() 類似,只是修改後的結果減少或組合 成一個單一的結果。
- Concurrent Filter 和 Filter-Reduce
QtConcurrent::filter():從容器中刪除所有滿足某個條件的item。
QtConcurrent::filtered():和 filter() 類似,只是它返回一個包含過濾內容的新容器。
QtConcurrent::filteredReduced():和 filtered() 類似,只是過濾後的結果減少或組合成一個單一的結果。
- Concurrent Run
QtConcurrent::run():在另一個執行緒中執行一個函式。
QFuture:表示非同步計算的結果
QFutureIterator:允許通過 QFuture 遍歷可用的結果
QFutureWatcher:允許使用訊號槽來監控一個 QFuture
QFutureSynchronizer:是一個方便的類,用於一些 QFutures 的自動同步
Qt Concurrent 支援多種相容 STL 的容器和迭代器型別,但是最好使用具有隨機訪問迭代器的 Qt 容器,例如:QList 或 QVector。map 和 filter 函式都接受容器和 begin/end 迭代器。
在 Qt Concurrent 迭代大量輕量級 items 的情況下,隨機訪問迭代器可以更快,因為它們允許跳過容器中的任何點。此外,使用隨機訪問迭代器允許 Qt Concurrent 通過 QFuture::progressValue() 和 QFutureWatcher::progressValueChanged() 來提供進度資訊。
非就地修改的函式(例如:mapped() 和 filtered()),在呼叫時會建立容器的副本。如果正在使用的是 STL 容器,此複製操作可能需要一段時間,在這種情況下,建議為容器指定 begin 和 end 迭代器。
Concurrent Map 和 Map-Reduce示例:
1 void add(int &num)
2 {
3 num +=1;
4 }
5
6 int mappedReducedFunction(const int& num)
7 {
8 return num + 1;
9 }
10
11 void ReduceFunction(int& result, const int& item)
12 {
13 result = item > result ? item : result;
14 }
15
16 {
17 QVector<int> vector;
18
19 for(int i=0; i<3; i++)
20 vector.append(i);
21
22 qDebug() << "start: " << vector;
23
24 QFuture<void> vFuture = QtConcurrent::map(vector, add);
25 vFuture.waitForFinished();
26
27 qDebug() << "map result: " << vector;
28
29 QFuture<int> iFuture = QtConcurrent::mappedReduced(vector, mappedReducedFunction, ReduceFunction);
30
31 qDebug() << "mappedReduced result: " << iFuture.result();
32 }
結果輸出:
start: QVector(0, 1, 2)
map result: QVector(1, 2, 3)
mappedReduced result: 4
QtConcurrent::mappedReduced() 類似於 QtConcurrent::mapped(),但是不是返回具有新結果的序列,而是使用 reduce 函式將結果組合成單個值。
reduce 函式必須是以下形式:
V function(T &result, const U &intermediate)
T 是最終結果的型別,U 是 map 函式的返回型別。注意: reduce 函式的返回值、返回型別沒有被使用。
對於 map 函式返回的每個結果,reduce 函式將被呼叫一次,並且應該將中間體合併到結果變數中。QtConcurrent::mappedReduced() 保證一次只有一個執行緒呼叫 reduce,所以沒有必要用一個 mutex 鎖定結果變數。
QtConcurrent::ReduceOptions 列舉提供了一種方法來控制 reduction 完成的順序。如果使用 QtConcurrent::UnorderedReduce(預設),順序是不確定的;而 QtConcurrent::OrderedReduce 確保 reduction 按照原始序列的順序完成。
Concurrent Filter Filter-Reduce 與 Concurrent Map Map-Reduce 使用基本一致。
QtConcurrent::run() 函式在一個單獨的執行緒中執行一個函式, 函式的返回值通過 QFuture API 提供。
Concurrent Run示例:
1 int add(int &num)
2 {
3 return ++num;
4 }
5
6 {
7 QFuture<int> future = QtConcurrent::run(add, 1);
8 future.waitForFinished();
9
10 qDebug() << "result: " << future.result();
11 }
結果輸出:
result: 2
上述兩個示例中,我們都是QFuture阻塞執行緒等待計算完成;QFuture 還提供了很多方法與正在進行的非同步呼叫進行互動。例如,使用 cancel() 函式取消計算;要暫停計算,使用 setPaused() 函式或 pause(),resume()、togglePaused() 便利函式之一。
注意:並非所有非同步計算都可以取消或暫停。例如,QtConcurrent::run() 返回的 future 不能被取消,但 QtConcurrent::mappedReduced() 返回的可以。