Qt:并发Map和Map-Reduce

1059 篇文章 285 订阅

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的更多信息,请参见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监视地图的状态。

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);
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
根据你提供的代码,这部分代码主要是创建了一个 `penColorComboBox` 下拉框,并添加了一些颜色选项。每个颜色选项都使用一个 QPixmap 来生成相应的图标,并设置了对应的颜色作为用户数据。 在 `MainWindow` 类中,通过连接 `penColorComboBox` 的 `currentIndexChanged` 信号到槽函数 `onPenColorChanged` 上,当用户选择不同的颜色时,槽函数会被触发。 以下是对你提供的代码进行一些修改和完善: ```cpp penColorComboBox = new QComboBox(this); QPixmap pix(16, 16); QPainter painter(&pix); painter.fillRect(0, 0, 16, 16, Qt::black); penColorComboBox->addItem(QIcon(pix), tr("黑色"), QColor(Qt::black)); painter.fillRect(0, 0, 16, 16, Qt::white); penColorComboBox->addItem(QIcon(pix), tr("白色"), QColor(Qt::white)); painter.fillRect(0, 0, 16, 16, Qt::red); penColorComboBox->addItem(QIcon(pix), tr("红色"), QColor(Qt::red)); painter.fillRect(0, 0, 16, 16, Qt::blue); penColorComboBox->addItem(QIcon(pix), tr("蓝色"), QColor(Qt::blue)); painter.fillRect(0, 0, 16, 16, Qt::green); penColorComboBox->addItem(QIcon(pix), tr("绿色"), QColor(Qt::green)); painter.fillRect(0, 0, 16, 16, Qt::yellow); penColorComboBox->addItem(QIcon(pix), tr("黄色"), QColor(Qt::yellow)); penColorComboBox->addItem(tr("无颜色"), QColor(Qt::transparent)); toolBar->addWidget(penColorComboBox); toolBar->setMovable(true); // 设置工具栏可移动 connect(penColorComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(onPenColorChanged(int))); void MainWindow::onPenColorChanged(int index) { QColor color = penColorComboBox->itemData(index, Qt::UserRole).value<QColor>(); area->setPenColor(color); } ``` 这里主要的修改是将 `penColorComboBox` 的命名更正为 `brushColorComboBox`,并将槽函数 `onpenColorchanged` 修改为 `onPenColorChanged`。同时,在槽函数中获取选中的颜色时,使用 `itemData` 函数获取对应的用户数据,并将其转换为 `QColor`。 另外,需要注意的是,在 `MainWindow` 类中必须定义一个 `onPenColorChanged` 的槽函数,以便在用户选择不同颜色时执行相应的操作。你需要根据实际需求,将获取到的颜色传递给画布类(例如 `area`)中的相应函数来设置绘画工具的颜色。 希望这可以帮助你在选择颜色后在画布上使用对应的颜色进行绘画。如果你有其他问题,请提供更多相关的代码或要求的信息。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值