目录
4.3 QtConcurrent::mappedReduced
4.5 QtConcurrent::blockingMapped
4.6 QtConcurrent:: blockingMappedReduced
6.3 QtConcurrent::mappedReduced()
1、Header: #include <QtConcrrent>
2、qmake: QT += concurrent
3、 详情描述
QtConcurrent::map(), QtConcurrent::mapped() 和 QtConcurrent::mappedReduced() 函数在一个序列中(例如:QList 或者 QVector )并行的运行计算。
QtConcurrent::map() 在原地修改序列;
QtConcurrent::mapped() 返回一个包含修改内容的新序列;
QtConcurrent::mappedReduced() 返回单个结果;
这些函数都是Qt并发框架的一部分。
上面的每一个函数都有一个阻塞变量,它返回最终结果,而不是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).
4 number functions
4.1 QtConcurrent::mapped
QtConcurrent::mapped() 接受一个输入序列和映射函数。然后对序列中的每个项调用这个映射函数,并返回一个包含映射函数返回值的新序列。
必须是如下格式:
U function(const T &t);
U和T可以是任意类型(可以相同),但是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文档。
如果想要修改一个序列,可使用QtConcrrent::map()。
4.2 QtConcurrent::map
使用 QtConcurrent::map() 可以修改一个序列,map()函数必须是以下形式:
U function(T &t);
注意:这里不会使用函数的返回值和返回类型。
使用map()类似于使用mapped():
void scale(QImage &image)
{
image = image.scaled(100, 100);
}
QList<QImage> images = ...;
QFuture<void> future = QtConcurrent::map(images, scale);
由于容器内容已被修改,QtConcrrent::map()不会通过QFuture返回任何结果。但是,仍然可以使用QFuture和QFutureWatcher来监视映射状态。
4.3 QtConcurrent::mappedReduced
QtConcurrent::mappedReduced() 类似于 QtConcurrent::mapped(),但不是返回一个带有新结果的序列,而是使用reduce函数讲结果组合成一个单独的值。
函数模版:
V function(T &result, const U &intermediate)
T是最终的结果类型,U是映射函数的返回类型。注意,reduce函数的返回值和返回类型没有被使用。
如下方式调用:
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函数,并且会将中间值合并到结果变量中。QtConcrrent::mappedReduced()保证每次只有一个线程会调用reduce,所以不需要使用互斥锁来锁定结果变量。QtConcurrent::ReduceOptions枚举类型提供一个控制顺序的方法。QtConcurrent::UnorderedReduce是默认的, 其顺序未定义, 而 QtConcurrent::OrderedReduce 确保按原始序列输出。
4.4 QtConcurrent::blockingMap
void QtConcurrent::blockingMap(Sequence &sequence, MapFunction function)
对每个项按顺序调用函数一次。该函数将向项传递一个引用,以便对项所做的任何修改都将依次显示。
注意:这个函数将阻塞直到序列中的所有项都被处理完。
void QtConcurrent::blockingMap(Iterator begin, Iterator end, MapFunction function)
从头到尾对每个项调用函数一次。该函数将向该元素传递一个引用,以便对该元素所做的任何修改都将出现在迭代器所属的序列中。
注意:这个函数将会阻塞,直到迭代器到达正在处理的序列的末尾。
4.5 QtConcurrent::blockingMapped
T QtConcurrent::blockingMapped(const Sequence &sequence, MapFunction function)
对序列中的每个项调用函数一次,并返回包含结果的序列。结果的类型将匹配我的MapFunction返回的类型。
注意:这个函数将阻塞直到序列中的所有项都被处理完。
T QtConcurrent::blockingMapped(ConstIterator begin, ConstIterator end, MapFunction function)
对每个条目从头到尾调用函数一次,并返回一个带有结果的容器。将容器类型指定为a模板参数,如下所示:
QList<int> int = QtConcurrent::blockingMapped<QList<int> >(beginIterator, endIterator, fn);
注意:这个函数将会阻塞,直到迭代器到达正在处理的序列的末尾。
4.6 QtConcurrent:: blockingMappedReduced
T QtConcurrent::blockingMappedReduced(const Sequence &sequence, MapFunction mapFunction, ReduceFunction reduceFunction, QtConcurrent::ReduceOptions reduceOptions = UnorderedReduce | SequentialReduce)
对每个项按顺序调用mapFunction一次。每个mapFunction的返回值被传递给reduceFunction。
注意,当mapFunction被并发调用时,每次只有一个线程会调用reduceFunction。reduceFunction的调用顺序由reduceOptions决定。
注意:这个函数将阻塞直到序列中的所有项都被处理完。
T QtConcurrent::blockingMappedReduced(ConstIterator begin, ConstIterator end, MapFunction mapFunction, ReduceFunction reduceFunction, QtConcurrent::ReduceOptions reduceOptions = UnorderedReduce | SequentialReduce)
对每个条目从头到尾调用mapFunction一次。每个mapFunction的返回值被传递给reduceFunction。
注意,当mapFunction被并发调用时,每次只有一个线程会调用reduceFunction。reduceFunction的调用顺序没有定义。
注意:这个函数将会阻塞,直到迭代器到达正在处理的序列的末尾。
5、API附加特征
5.1 使用迭代器代替容器
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);
5.2 阻塞变量
QList<QImage> images = ...;
// 每次调用都会被阻塞,直到调用完成
QList<QImage> future = QtConcurrent::blockingMapped(images, scaled);
QtConcurrent::blockingMap(images, scale);
QImage collage = QtConcurrent::blockingMappedReduced(images, scaled, addToCollage);
注意:上述的结果类型不是 QFuture 对象,而是实际结果类型(在这种情况下,是 QList<QImage>
和 QImage)。
5.3 使用成员函数
QtConcurrent::map()、QtConcurrent::mapped() 和 QtConcurrent::mappedReduced() 接受成员函数的指针,成员函数类类型必须与存储在序列中的类型匹配:
// Squeeze all strings in a QStringList.
QStringList strings = ...;
QFuture<void> squeezedStrings = QtConcurrent::map(strings, &QString::squeeze);
// 交换 images 列表中图片所有像素的 rgb 值
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(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);
5.4 使用函数对象
QtConcurrent::map()、QtConcurrent::mapped() 和 QtConcurrent::mappedReduced() 接受函数对象,可用于向函数调用添加状态。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))
5.5 多个函数参数
如果你想要使用带多个参数的map函数,你可以使用Lamada函数或者std::bind()将其转化为带一个参数的函数。
例如:我们将使用
QImage QImage::scaledToWidth(int width, Qt::TransformationMode) const;
scaledToWidth有三个参数(包含this指针),不能直接与QtConcrrent::mapped()一起使用,因为QtConcrrent::mapped()期望一个只有一个参数的函数。如要在QtConcrrent::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);
6、代码示例
6.1 QtConcurrent::mapped()
extern int func(const int &arg){ return arg+1; }; QList<int> list; list << 1 << 2 << 3 << 4 << 5 << 6; QFuture<int> future = QtConcurrent::mapped(list, func); qDebug() << "list: " << list << ", future:" << future.results(); //输出: list: (1, 2, 3, 4, 5, 6) , future: (2, 3, 4, 5, 6, 7)
6.2 QtConcurrent::map()
QList<int> list;
list << 1 << 2 << 3 << 4 << 5;
qDebug() << "start list: " << list ;
QFuture<void> future = QtConcurrent::map(list, func);
QFutureWatcher<void> *watcher = new QFutureWatcher<void>(this);
watcher->setFuture(future);
connect(watcher, &QFutureWatcher<void>::finished, [=](){
qDebug() << "finished list: " << list ;
});
//输出:
//start list: (1, 2, 3, 4, 5)
//finished list: (2, 3, 4, 5, 6)
6.3 QtConcurrent::mappedReduced()
extern int func(const int &arg){
return arg + 1;
};
void addCollage(int &result, const int &arg)
{
if(result < arg)
result = arg;
}
QList<int> list;
list << 1 << 2 << 3 << 4 << 5;
QFuture<int> collage = QtConcurrent::mappedReduced(list, func, addCollage);
collage.waitForFinished();
qDebug() << collage.result(); //6