并发映射和映射-Reduce
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<QImage> 和 QImage)。
并发映射
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()。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-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 函数,并将中间 结果合并到结果变量中。QtConcurrent::mappedReduced() 保证每次只有一个线程调用 reduce,因此无需使用互斥来锁定结果变量。QtConcurrent::ReduceOptions 枚举提供了一种控制还原顺序的方法。如果使用QtConcurrent::UnorderedReduce (默认值),则顺序未定义,而QtConcurrent::OrderedReduce 可确保按照原始序列的顺序进行还原。
其他应用程序接口功能
使用迭代器代替序列
上述每个函数都有一个使用迭代器范围而非序列的变体。使用方法与序列变体相同:
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<QImage> 和 QImage)。
使用成员函数
QtConcurrent::map()、QtConcurrent::mapped()和 QtConcurrent::mappedReduced() 接受指向成员函数的指针。成员函数类的类型必须与存储在序列中的类型相匹配:
// 在 QStringList 中挤压所有字符串。QStringListstrings= .....;QFuture<void>squeezedStrings=QtConcurrent::map(strings, &QString::squeeze);// 交换图像列表中所有像素的 rgb 值。QList<QImage>images= .....;QFuture<QImage>bgrImages=QtConcurrent::mapped(images,static_cast<QImage(QImage::*)()const&>(&QImage::rgbSwapped));// 创建一个列表中所有字符串长度的集合。QStringListstrings= .....;QFuture<QSet<int>>wordLengths=QtConcurrent::mappedReduced(strings, &QString::length、 qOverload<const int&>(&QSet<int>::insert));
注意qOverload 的使用。需要使用它来解决有多个重载的方法的歧义问题。
还请注意,在使用 QtConcurrent::mappedReduced() 时,您可以自由混合使用普通函数和成员函数:
// Can mix normal functions and member functions with QtConcurrent::mappedReduced( );QStringListstrings= .....;QFuture<int>averageWordLength=QtConcurrent::mappedReduced(strings, &QStringextern intcolorDistribution(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));
还原函数也支持函数对象:
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() 期望使用一个参数的函数。要在 QtConcurrent::mapped() 中使用 QImage::scaledToWidth(),我们必须提供宽度值和转换模式:
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);
© 2025 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.