Qt Concurrent 并发 Map 和 Map-Reduce

并发 Map 和 Map-Reduce

上述每个函数都有一个阻塞变体,它返回最终结果而不是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)。

并发 Map

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 的详细信息,请参阅QFutureQFutureWatcher 文档。

如果您想就地修改序列,请使用 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 返回任何结果。不过,您仍然可以使用QFutureQFutureWatcher 来监控映射的状态。

并发 Map-Reduce

QtConcurrent::mappedReduced() 类似于 QtConcurrent::mapped(),但不是返回包含新结果的序列,而是使用 reduce 函数将结果合并为一个值。

reduce 函数的形式必须是

复制代码
V function(T &result, const U &intermediate)

T 是最终结果的类型,U 是映射函数的返回类型。注意,不使用 reduce 函数的返回值和返回类型。

像这样调用 QtConcurrent::mappedReduced():

复制代码
QImage scaled(const QImage &image)
{
    return image.scaled(100, 100);
}

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() 接受指向成员函数的指针。成员函数类的类型必须与存储在序列中的类型相匹配:

复制代码
// 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() 时,您可以自由混合使用普通函数和成员函数:

复制代码
// 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));

还原函数也支持函数对象:

复制代码
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);

Concurrent Map and Map-Reduce | Qt Concurrent 6.8.2

相关推荐
我是一只小青蛙8881 小时前
JavaScript DOM操作全解析
开发语言·javascript·ecmascript
SunkingYang8 小时前
QT编译报错:使用Lambda表达式作为槽函数,报错‘xxx‘ in capture list does not name a variable
qt·list·报错·lambda表达式·槽函数·in capture list·does not name
你怎么知道我是队长9 小时前
C语言---头文件
c语言·开发语言
期待のcode9 小时前
Java虚拟机的运行模式
java·开发语言·jvm
hqwest9 小时前
码上通QT实战25--报警页面01-报警布局设计
开发语言·qt·qwidget·ui设计·qt布局控件
a程序小傲9 小时前
京东Java面试被问:动态规划的状态压缩和优化技巧
java·开发语言·mysql·算法·adb·postgresql·深度优先
HellowAmy9 小时前
我的C++规范 - 玩一个小游戏
开发语言·c++·代码规范
徐先生 @_@|||10 小时前
Palantir Foundry 五层架构模型详解
开发语言·python·深度学习·算法·机器学习·架构
SunkingYang11 小时前
QT中如何遍历QStringList
qt·解析·遍历·方式·读取·qstringlist
tang7778911 小时前
爬虫如何绕过绕过“5秒盾”Cloudflare:从浏览器指纹模拟到Rust求解之不完全指南
开发语言·爬虫·rust·cloudflare