1. 程式人生 > >Qt 之 Concurrent Map 和 Map-Reduce

Qt 之 Concurrent Map 和 Map-Reduce

簡述

QtConcurrent::map()、QtConcurrent::mapped() 和 QtConcurrent::mappedReduced() 函式對一個序列中(例如:QList、QVector)的專案並行地進行計算。QtConcurrent::map() 就地修改一個序列,QtConcurrent::mapped() 返回一個包含修改內容的新序列,QtConcurrent::mappedReduced() 返回一個單一的結果。

上述的每個函式都有一個 blocking 變數,其返回的是最終結果,而不是一個 QFuture。可以用和非同步變數同樣的方式來使用它們。

QList<QImage> images = ...
; // 每次呼叫都會被阻塞,直到整個操作完成 QList<QImage> future = QtConcurrent::blockingMapped(images, scaled); QtConcurrent::blockingMap(images, scale); QImage collage = QtConcurrent::blockingMappedReduced(images, scaled, addToCollage);

注意:上述的結果型別不是 QFuture 物件,而是實際結果型別(在這種情況下,是 QList<QImage>和 QImage)。

|

Concurrent Map

QtConcurrent::mapped() 接受一個輸入序列和一個 map 函式,該 map 函式被序列中的每一項呼叫,並返回一個包含 map 函式返回值的新序列。

map 函式必須是以下形式:

U function(const T &t);

T 和 U 可以是任意型別(它們甚至可以是同一型別),但是 T 必須匹配儲存在序列中的型別,該函式返回修改或對映的內容。

下面示例,介紹瞭如何為序列中的每一項應用一個 scale 函式:

QImage scaled(const QImage &image)
{
    return image.scaled(100
, 100); } QList<QImage> images = ...; QFuture<QImage> thumbnails = QtConcurrent::mapped(images, scaled);

map 的結果通過 QFuture 提供。有關如何在應用程式中使用 QFuture 的更多資訊,請參閱 QFuture 和 QFutureWatcher 文件。

如果想就地修改一個序列,使用 QtConcurrent::map()。map 函式必須是以下形式:

U function(T &t);

注意: map 函式的返回值、返回型別沒有被使用。

使用 QtConcurrent::map() 和使用 QtConcurrent::mapped() 類似:

void scale(QImage &image)
{
    image = image.scaled(100, 100);
}

QList<QImage> images = ...;
QFuture<void> future = QtConcurrent::map(images, scale);

由於該序列被就地修改,QtConcurrent::map() 不通過 QFuture 返回任何結果。然而,仍然可以使用 QFuture 和 QFutureWatcher 監控 map 的狀態。

Concurrent Map-Reduce

QtConcurrent::mappedReduced() 類似於 QtConcurrent::mapped(),但是不是返回具有新結果的序列,而是使用 reduce 函式將結果組合成單個值。

reduce 函式必須是以下形式:

V function(T &result, const U &intermediate)

T 是最終結果的型別,U 是 map 函式的返回型別。注意: reduce 函式的返回值、返回型別沒有被使用。

呼叫 QtConcurrent::mappedReduced() 如下所示:

void addToCollage(QImage &collage, const QImage &thumbnail)
{
    QPainter p(&collage);
    static QPoint offset = QPoint(0, 0);
    p.drawImage(offset, thumbnail);
    offset += ...;
}

QList<QImage> images = ...;
QFuture<QImage> collage = QtConcurrent::mappedReduced(images, scaled, addToCollage);

對於 map 函式返回的每個結果,reduce 函式將被呼叫一次,並且應該將中間體合併到結果變數中。QtConcurrent::mappedReduced() 保證一次只有一個執行緒呼叫 reduce,所以沒有必要用一個 mutex 鎖定結果變數。QtConcurrent::ReduceOptions 列舉提供了一種方法來控制 reduction 完成的順序。如果使用 QtConcurrent::UnorderedReduce(預設),順序是不確定的;而 QtConcurrent::OrderedReduce 確保 reduction 按照原始序列的順序完成。

附加 API 功能

使用迭代器而不是序列

上述每個函式都有一個變數,需要一個迭代器範圍,而不是一個序列。可以用和序列變數同樣的方式來使用它們。

QList<QImage> images = ...;

QFuture<QImage> thumbnails = QtConcurrent::mapped(images.constBegin(), images.constEnd(), scaled);

// map 僅就地執行在 non-const 迭代器上
QFuture<void> future = QtConcurrent::map(images.begin(), images.end(), scale);

QFuture<QImage> collage = QtConcurrent::mappedReduced(images.constBegin(), images.constEnd(), scaled, addToCollage);

Blocking 變數

上述每個函式能有一個 blocking 變數,其返回的是最終結果,而不是一個 QFuture。可以用和非同步變數同樣的方式來使用它們。

QList<QImage> images = ...;

// 每次呼叫都會被阻塞,直到整個操作完成
QList<QImage> future = QtConcurrent::blockingMapped(images, scaled);

QtConcurrent::blockingMap(images, scale);

QImage collage = QtConcurrent::blockingMappedReduced(images, scaled, addToCollage);

注意:上述的結果型別不是 QFuture 物件,而是實際結果型別(在這種情況下,是 QList<QImage>和 QImage)。

使用成員函式

QtConcurrent::map()、QtConcurrent::mapped() 和 QtConcurrent::mappedReduced() 接受成員函式的指標,成員函式類型別必須與儲存在序列中的型別匹配:

// 擠壓 QStringList 中的所有字串
QStringList strings = ...;
QFuture<void> squeezedStrings = QtConcurrent::map(strings, &QString::squeeze);

// 交換 images 列表中圖片所有畫素的 rgb 值
QList<QImage> images = ...;
QFuture<QImage> bgrImages = QtConcurrent::mapped(images, &QImage::rgbSwapped);

// 建立一個列表中所有字串長度的集合  
QStringList strings = ...;
QFuture<QSet<int> > wordLengths = QtConcurrent::mappedReduced(strings, &QString::length, &QSet<int>::insert);

注意:當使用 QtConcurrent::mappedReduced() 時,可以自由地混合使用正常函式和成員函式:

// 可以使用 QtConcurrent::mappedReduced() 混合正常函式和成員函式

// 計算字串列表的平均長度
extern void computeAverage(int &average, int length);
QStringList strings = ...;
QFuture<int> averageWordLength = QtConcurrent::mappedReduced(strings, &QString::length, computeAverage);

// 建立一個列表中所有影象顏色分佈的集合
extern int colorDistribution(const QImage &string);
QList<QImage> images = ...;
QFuture<QSet<int> > totalColorDistribution = QtConcurrent::mappedReduced(images, colorDistribution, QSet<int>::insert);

使用函式物件

QtConcurrent::map()、QtConcurrent::mapped() 和 QtConcurrent::mappedReduced() 接受函式物件,可用於向函式呼叫新增狀態。result_type typedef 必須定義結果函式呼叫操作符的型別:

struct Scaled
{
    Scaled(int size)
    : m_size(size) { }

    typedef QImage result_type;

    QImage operator()(const QImage &image)
    {
        return image.scaled(m_size, m_size);
    }

    int m_size;
};

QList<QImage> images = ...;
QFuture<QImage> thumbnails = QtConcurrent::mapped(images, Scaled(100));

使用繫結函式引數

如果想使用一個接受多個引數的 map 函式,可以使用 std::bind() 將其轉換到接受一個引數的函式。如果 C++11 支援不可用,boost::bind()std::tr1::bind() 是合適的替代品。

例如,使用 QImage::scaledToWidth():

QImage QImage::scaledToWidth(int width, Qt::TransformationMode) const;

scaledToWidth 接收三個引數(包括“this”指標),不能直接使用 QtConcurrent::mapped(),因為 QtConcurrent::mapped() 期望一個接收一個引數的函式。為了 QImage::scaledToWidth() 和 QtConcurrent::mapped() 一起使用,必須為 width 和 transformation mode 提供一個值:

std::bind(&QImage::scaledToWidth, 100, Qt::SmoothTransformation)

std::bind() 的返回值是一個具有以下簽名的函式物件(functor):

QImage scaledToWith(const QImage &image)

這符合 QtConcurrent::mapped() 期望的,完整的示例變為:

QList<QImage> images = ...;
QFuture<QImage> thumbnails = QtConcurrent::mapped(images, std::bind(&QImage::scaledToWidth, 100 Qt::SmoothTransformation));

更多參考

相關推薦

Qt Concurrent Map Map-Reduce

簡述 QtConcurrent::map()、QtConcurrent::mapped() 和 QtConcurrent::mappedReduced() 函式對一個序列中(例如:QList、QVector)的專案並行地進行計算。QtConcurrent::m

Java FP: Java中函數語言程式設計的MapFold(Reduce)

原文連結 作者:  Cyrille Martraire  譯者: 李璟([email protected]) 在函數語言程式設計中,Map和Fold是兩個非常有用的操作,它們存在於每一個函數語言程式設計語言中。既然Map和Fold操作如此強大和重要,但是Java語言缺乏Map和Fol

Java FP(Java8): Java中函數語言程式設計的MapFold(Reduce)

public double totalAmount(List<Double> amounts) { double sum = 0; for(double amount : amounts) { sum += amount; } return sum

QTINI檔案登錄檔操作方法學習筆記

INI檔案格式 節[section] 引數(KEY/VALUE)   name=value 註釋 註釋使用分號表示(;)。在分號後面的文字,直到該行結尾都全部為註釋 QCoreApplication::applicationDirPath()為應用程式當前的絕

03-封裝BeanUtil工具類(javabean轉mapmap轉javabean物件)

package com.oa.test; import java.beans.BeanInfo; import java.beans.IntrospectionException; import java.beans.Introspector; import java.beans.PropertyDe

關於map巢狀mapmap巢狀list(轉載https://blog.csdn.net/mustbehard/article/details/17310043)

import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set;

MapMap.entry詳解

一、Map.Entry說明 Map是java中的介面,Map.Entry是Map的一個內部介面。 Map提供了一些常用方法,如keySet()、entrySet()等方法,keySet()方法返回值是Map中key值的集合;entrySet()的返回值也是返回一個Set集合,此集合的型別為M

Qt執行緒QObject

前面兩個章節我們從事件迴圈和執行緒類庫兩個角度闡述有關執行緒的問題。本章我們將深入執行緒間得互動,探討執行緒和QObject之間的關係。在某種程度上,這才是多執行緒程式設計真正需要注意的問題。 現在我們已經討論過事件迴圈。我們說,每一個 Qt 應用程式至

Qt訊號signals槽slots詳解

        學習到自定義訊號和槽的時候經常編譯不過去,前邊一篇解決了Q_OBJECT編譯的問題,這裡詳細說明了slots和signals。 1、signals前面不可加public、private和protected進行修飾;slots前面可以

Qt Concurrent Run

簡述 QtConcurrent::run() 函式在一個單獨的執行緒中執行一個函式, 函式的返回值通過 QFuture API 提供。 | 在單獨的執行緒中執行函式 要在另一個執行緒中執行函式,使用 QtConcurrent::run():

QtConcurrent框架

簡述 QtConcurrent 名稱空間提供了高階 API,使得可以在不使用低階執行緒原語(例如:互斥、讀寫鎖、等待條件或訊號量)的情況下編寫多執行緒程式,使用 QtConcurrent 編寫的程式根據可用的處理器核心數自動調整所使用的執行緒數。這意味著,當在未來部署多核系統時,現在編寫的應用程式將繼續

Qt Concurrent 框架

簡述 QtConcurrent 名稱空間提供了高階 API,使得可以在不使用低階執行緒原語(例如:互斥、讀寫鎖、等待條件或訊號量)的情況下編寫多執行緒程式,使用 QtConcurrent 編寫的程式根據可用的處理器核心數自動調整所使用的執行緒數。這意味著,當在

ECMAScript5/6新特性mapreduce

/*map和reduce*/ //map():接收一個函式,將原陣列的所有元素用函式處理後放入新陣列返回 //例如將一個字串陣列轉為int陣列 let crr = ['1','2','3']; crr = crr.map(e=>parseInt(e)); console.log(typeof(

pythonmapreduce的區別以及zip使用

①從引數方面來講:map()函式:map()包含兩個引數,第一個是引數是一個函式,第二個是序列(列表或元組)。其中,函式(即map的第一個引數位置的函式)可以接收一個或多個引數。reduce()函式:reduce() 第一個引數是函式,第二個是 序列(列表或元組)。但是,其函

Python自學筆記-mapreduce函數(來自廖雪峰的官網Python3)

求和 rabl style 序列 list port lambda char att 感覺廖雪峰的官網http://www.liaoxuefeng.com/裏面的教程不錯,所以學習一下,把需要復習的摘抄一下。 以下內容主要為了自己復習用,詳細內容請登錄廖雪峰的官網查看。

Python中mapreduce函數

courier ref tail erl position 必須 第一個 http title ①從參數方面來講: map()函數: map()包含兩個參數,第一個是參數是一個函數,第二個是序列(列表或元組)。其中,函數(即map的第一個參數位置的函數)可以接收一個或多個參

hive的mrmap-reduce基本設計模式

key format values 模式 none columns lan pac ... (原創文章,謝絕轉載~) hive可以使用 explain 或 explain extended (select query) 來看mapreduce執行的簡要過程描述。expla

利用mapreduce編寫一個str2float函數,把字符串'123.456'轉換成浮點數123.456:

AR 浮點數 n) 失敗 FN cto fun [1] str2 利用map和reduce編寫一個str2float函數,把字符串‘123.456‘轉換成浮點數123.456: # -*- coding: utf-8 -*- from functools import r

Python的mapreduce

too reduce rom from brush () 下一個 list 生成式 map(): map()函數接收兩個參數,一個是函數,一個是Iterable >>> l = [i for i in range(10)] #[0, 1, 2, 3,

Yarn中的MapReduce的優化

科技;大數據;yarn通過Hive執行的批次任務處理失敗,Spark中報的錯誤日誌如下: [plain] view plain copyERROR : Failed to monitor Job[ 3] with exception ‘java.lang.IllegalStateException(RPC c