Qt中的 Concurrent 模块为我们提供了在一个序列容器类型针对每一个元素的多线程并行运算, 比如 QList 、 QVector 。
QFuture<void> map(Sequence &sequence, MapFunctor map)
下面是一个简单的使用示例:
void scale(QImage &image)
{
image = image.scaled(100, 100);
}
QList<QImage> images = ...;
QFuture<void> future = QtConcurrent::map(images, scale);
该示例中,多线程对 QList<QImage> 容器中的每一个 QImage 缩放到 100 * 100 的尺寸。结果会覆盖掉原容器中的元素。
下面是使用 QtConcurrent::mapped 的例子
QImage scaled(const QImage &image)
{
return image.scaled(100, 100);
}
QList<QImage> images = ...;
QFuture<QImage> thumbnails = QtConcurrent::mapped(images, scaled);
这里同样也是对列表中的 QImage 进行缩放到 100 * 100 大小,但是容器本身的内容没有改变。
使用如下代码获取运算结果:
funcFunture2.waitForFinished(); // 等待运算处理完成
thumbnails.results(); // 获取运算结果
mappedReduced() 类似于 QtConcurrent::mapped() , 但是它不是返回一个带有新结果的序列,而是使用reduce函数将结果组合成一个单独的值。
它的函数基本形式如下:
template <typename Sequence, typename MapFunctor, typename ReduceFunctor>
QFuture<typename QtPrivate::ReduceResultType<ReduceFunctor>::ResultType>
mappedReduced(const Sequence &sequence,
MapFunctor map,
ReduceFunctor reduce,
ReduceOptions options = ReduceOptions(UnorderedReduce | SequentialReduce))
下面是一个示例:
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);
这里 images 中的每一个元素执行完 scaled 函数后的序列, 序列中的每一个元素再执行函数 addToCollage ,最后将计算结构返回。
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);
map 、mapped和mappedReduced为非阻塞形式的多线程执行,可以使用 QFuture 和 QFutureWatcher 作异步通知。但是Qt同样也提供了阻塞版本的函数:
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 ,而是真实的结果类型。 (在这个示例中,返回 QImage 和 QList<QImage>)
// 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, &QImage::rgbSwapped);
// create a set of the lengths of all strings in a list
QStringList strings = ...;
QFuture<QSet<int> > wordLengths = QtConcurrent::mappedReduced(string, &QString::length, &QSet<int>::insert);
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);
比如这个函数
QImage QImage::scaledToWidth(int width, Qt::TransformationMode) const;
可以借助 lambda 表达式处理参数
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);