并发映射和映射-归约
QtConcurrent::map(), QtConcurrent::mapped() 和 QtConcurrent::mappedReduced() 函数在如QList等序列的项上并行执行计算。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
并发映射
QtConcurrent::mapped()接受一个输入序列和一个映射函数。然后对序列中的每个项调用映射函数,并返回一个包含映射函数返回值的新序列。
映射函数的格式必须为
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);
映射的结果通过 QFuture 提供。有关如何使用 QFuture 的一般信息,请参阅 QFuture 和 QFutureWatcher 文档。
如果要在原地修改序列,请使用 QtConcurrent::map()。然后映射函数必须为以下格式
U function(T &t);
请注意,映射函数的返回值和返回类型不会使用。
使用 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 来监控映射的状态。
并发映射-归约
QtConcurrent::mappedReduced() 与 QtConcurrent::mapped() 类似,但不是返回包含新结果的序列,而是使用归约函数将结果组合成一个单独的值。
归约函数的格式必须为
V function(T &result, const U &intermediate)
T 是最终结果类型,U 是映射函数的返回类型。请注意,归约函数的返回值和返回类型不会使用。
这样调用 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,因此使用互斥锁锁定结果变量是不必要的。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 = ...; // 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
使用成员函数
QtConcurrent::map()、QtConcurrent::mapped()和QtConcurrent::mappedReduced()接受成员函数的指针。成员函数的类类型必须与序列中存储的类型匹配
// Squeeze all strings in a QStringList. QStringList strings = ...; QFuture<void> squeezedStrings = QtConcurrent::map(strings, &QString::squeeze); // Swap the rgb values of all pixels on a list of images. QList<QImage> images = ...; QFuture<QImage> bgrImages = QtConcurrent::mapped(images, static_cast<QImage (QImage::*)() const &>(&QImage::rgbSwapped)); // Create a set of the lengths of all strings in a list. QStringList strings = ...; QFuture<QSet<int>> wordLengths = QtConcurrent::mappedReduced(strings, &QString::length, qOverload<const int&>(&QSet<int>::insert));
注意使用qOverload。这是解决具有多个重载的方法的歧义所需的。
此外,当使用QtConcurrent::mappedReduced()时,可以自由混合使用普通函数、成员函数和lambda表达式。
// Can mix normal functions and member functions with QtConcurrent::mappedReduced(). // Compute the average length of a list of strings. extern void computeAverage(int &average, int length); QStringList strings = ...; QFuture<int> averageWordLength = QtConcurrent::mappedReduced(strings, &QString::length, computeAverage); // Create a set of the color distribution of all images in a list. extern int colorDistribution(const QImage &string); QList<QImage> images = ...; QFuture<QSet<int>> totalColorDistribution = QtConcurrent::mappedReduced(images, colorDistribution, qOverload<const int&>(&QSet<int>::insert));
使用函数对象
QtConcurrent::map()、QtConcurrent::mapped()和QtConcurrent::mappedReduced()接受用于map函数的函数对象。这些函数对象可以用于添加状态到函数调用中
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(images, Scaled(100), ImageTransform(), QtConcurrent::SequentialReduce);
使用Lambda表达式
QtConcurrent::map()、QtConcurrent::mapped()和QtConcurrent::mappedReduced()接受用于map和reduce函数的lambda表达式
QList<int> vector { 1, 2, 3, 4 }; QtConcurrent::blockingMap(vector, [](int &x) { x *= 2; }); int size = 100; QList<QImage> images = ...; QList<QImage> thumbnails = QtConcurrent::mapped(images, [&size](const QImage &image) { return image.scaled(size, size); } ).results();
当使用QtConcurrent::mappedReduced()或QtConcurrent::blockingMappedReduced()时,可以自由混合使用普通函数、成员函数和lambda表达式。
QList<QImage> collage = QtConcurrent::mappedReduced(images, [&size](const QImage &image) { return image.scaled(size, size); }, addToCollage ).results();
还可以将lambda作为reduce对象传递
QList<QImage> collage = QtConcurrent::mappedReduced(images, [&size](const QImage &image) { return image.scaled(size, size); }, [](QImage &result, const QImage &value) { // do some transformation } ).results();
包装多个参数的函数
如果您想使用接受多个参数的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);
© 2024 Qt公司有限公司。本文档中的文档贡献是各自所有者的版权。本文档是根据自由软件基金会发布的GNU自由文档许可版本1.3的条款许可的。Qt及其相关徽标是芬兰以及/或在全世界其他国家的Qt公司有限公司的商标。所有其他商标均为其各自所有者的财产。