QtConcurrent::map()、QtConcurrent::mapped()和QtConcurrent::mappedReduced()函數在一個序列中(例如:QList或QVector)的元素上並行地運行計算。QtConcurrent::map()直接修改一個序列,QtConcurrent::mapped()返回一個包含修改內容的新序列,QtConcurrent::mappedReduced()返回一個單獨的結果。
這些函數是Qt之Concurrent框架的一部分。
上述每個函數都有一個blocking變量,其返回最終結果而不是一個QFuture。以和異步變量同樣的方式來使用它們。
QList<QImage> images = ...;
// 每一個都調用blocks,直到整個操作完成
QList<QImage> future = QtConcurrent::blockingMapped(images, scaled);
QtConcurrent::blockingMap(images, scale);
QImage collage = QtConcurrent::blockingMappedReduced(images, scaled, addToCollage);
注意:上述的結果類型不是QFuture對象,而是實際結果類型(在這種情況下,QList<QImage>
和QImage)。
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和QFutureWatcher的文檔,了解更多關於程序中如何使用QFutured的內容。
如果想直接修改一個序列,使用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的狀態。
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);
reduce函數將由map函數返回的每個結果調用一次,並且應該合並中間體到結果變量。QtConcurrent::mappedReduced()可以保證保證一次只有一個線程調用reduce,所以沒有必要用一個mutex鎖定結果變量。QtConcurrent::ReduceOptions枚舉提供了一種方法來控制reduction完成的順序。如果使用了QtConcurrent::UnorderedReduce(默認),順序是不確定的;而QtConcurrent::OrderedReduce確保reduction按照原始序列的順序完成。
上述每個函數都有一個變量,需要一個迭代器范圍,而不是一個序列。以和序列變量同樣的方式來使用它們。
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變量,其返回最終結果而不是一個QFuture。以和異步變量同樣的方式來使用它們。
QList<QImage> images = ...;
// 每一個都調用blocks,直到整個操作完成
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);
// 交換一個列表中的圖片所有像素的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() with 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));