QtConcurrent :: map(),QtConcurrent :: mapped()和QtConcurrent :: mappedReduced()
函数对比如QList或者Qvector之类的项目并行运行计算。
QtConcurrent :: map()
就地修改序列QtConcurrent :: mapped()
返回包含修改内容的新序列QtConcurrent :: mappedReduced()
返回单个结果
这些功能是Qt Concurrent
框架的一部分
上面的每个函数都有一个阻塞变量,该变量返回最终结果而不是QFuture
。您以与异步变体相同的方式使用它们
QList<QImage> images = ...;
// Each call blocks until the entire operation is finished.
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函数必须采用如下形式:
U function(const T &t);
T和U可以是任何类型(甚至可以是同一类型),但是T必须与序列中存储的类型匹配。该函数返回修改或映射的内容。
本示例说明如何将缩放功能应用于序列中的所有项目:
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
监视地图的状态。
Concurrent Map-Reduce
QtConcurrent::mappedReduced()
与 QtConcurrent::mapped(),
相似,但是不是使用新的结果返回序列,而是使用reduce函数将结果合并为一个值。
reduce函数的形式必须为:
V function(T &result, const U &intermediate)
T是最终结果的类型,U是映射函数的返回类型。请注意,未使用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函数将被调用一次,并且应将中间函数合并到result变量中。QtConcurrent :: mappedReduced()
保证一次只有一个线程将调用reduce
,因此不需要使用互斥锁来锁定结果变量。该QtConcurrent :: ReduceOptions
枚举提供了一种方法来控制它的降低完成的顺序。如果使用QtConcurrent :: UnorderedReduce
(默认设置),则顺序是不确定的,而QtConcurrent :: OrderedReduce
可确保按原始序列的顺序进行缩小。
其他API功能
使用迭代器代替序列
上面的每个函数都有一个采用迭代器范围而不是序列的变量。您以与序列变体相同的方式使用它们:
QList<QImage> images = ...;
QFuture<QImage> thumbnails = QtConcurrent::mapped(images.constBegin(), images.constEnd(), scaled);
// Map in-place only works on non-const iterators.
QFuture<void> future = QtConcurrent::map(images.begin(), images.end(), scale);
QFuture<QImage> collage = QtConcurrent::mappedReduced(images.constBegin(), images.constEnd(), scaled, addToCollage);
阻塞变量
上面的每个函数都有一个阻塞变量,该变量返回最终结果而不是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)。
使用成员函数
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()接受map函数的函数对象。这些函数对象可用于将状态添加到函数调用中。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));
对于reduce函数,不直接支持函数对象。但是,当明确指定归约结果的类型时,可以使用函数对象:
struct ImageTransform
{
void operator()(QImage &result, const QImage &value);
};
QFuture<QImage> thumbNails =
QtConcurrent::mappedReduced<QImage>(images,
Scaled(100),
ImageTransform(),
QtConcurrent::SequentialReduce);
包装函数需要多个参数
如果要使用带有多个参数的map函数,则可以使用lambda函数或std::bind()将其转换为带有一个参数的函数。
例如,我们将使用QImage :: scaledToWidth():
QImage QImage::scaledToWidth(int width, Qt::TransformationMode) const;
scaledToWidth具有三个参数(包括“ this”指针),因此不能直接与QtConcurrent :: mapped()一起使用,因为QtConcurrent :: mapped()需要一个带有一个参数的函数。要将QImage :: scaledToWidth()与QtConcurrent :: mapped()结合使用,我们必须为width和转换模式提供一个值:
QList<QImage> images = ...;
std::function<QImage(const QImage &)> scale = [](const QImage &img) {
return img.scaledToWidth(100, Qt::SmoothTransformation);
};
QFuture<QImage> thumbnails = QtConcurrent::mapped(images, scale);