Concurrent Filter and Filter-Reduce
The QtConcurrent::filter(), QtConcurrent::filtered() 和 QtConcurrent::filteredReduced() 函数通过并行计算过滤容器(如 QList 或 QVector) 中每个元素. QtConcurrent::filter() 直接修改容器, QtConcurrent::filtered() 返回包含已过滤元素的新容器, QtConcurrent::filteredReduced() 返回单个结果.
这些函数是 Qt Concurrent 框架的一部分.
上述函数都有一个对应的阻塞函数, 直接返回最终结果, 而不是 QFuture. 使用同步函数的方式与异步函数相同.
QStringList strings = ...; // each call blocks until the entire operation is finished QStringList lowerCaseStrings = QtConcurrent::blockingFiltered(strings, allLowerCase); QtConcurrent::blockingFilter(strings, allLowerCase); QSet<QString> dictionary = QtConcurrent::blockingFilteredReduced(strings, allLowerCase, addToDictionary);
注意: 上述代码的返回结果不是 QFuture 对象, 而是真正的类型结果 (QStringList 和 QSet<QString>).
Concurrent Filter
QtConcurrent::filtered() 的参数是一个序列容器和一个过滤函数. 这个函数为容器中的每个元素调用过滤函数, 返回一个包含过滤值的新序列.
过滤函数形式必须如下:
bool function(const T &t);
T必须与序列容器中的元素类型一致. 如果过滤函数返回 true
, 容器保留元素; 返回false, 容器删除元素.
下列示例显示如何筛选 QStringList中所有的小写字母:
bool allLowerCase(const QString &string) { return string.lowered() == string; } QStringList strings = ...; QFuture<QString> lowerCaseStrings = QtConcurrent::filtered(strings, allLowerCase);
filter的计算结果可以通过 QFuture获取. 详见 QFuture , QFutureWatcher.
如果你想修改容器序列, 使用 QtConcurrent::filter():
QStringList strings = ...; QFuture<void> future = QtConcurrent::filter(strings, allLowerCase);
注意: 上述函数的返回值和返回类型未使用.
QtConcurrent::filter() 直接修改容器元素, 没有通过 QFuture返回任何值. 然而, 你仍然可以使用 QFuture 和 QFutureWatcher 监控filter()状态.
Concurrent Filter-Reduce
QtConcurrent::filteredReduced() 与 QtConcurrent::filtered()类似, 但是使用新的类型结果代替容器, 结果是使用reduce函数组合成一个简单值.
reduce函数必须如下形式:
V function(T &result, const U &intermediate)
T类型是最终结果, U是函数的返回类型. 注意: reduce函数的返回值和返回类型未使用.
如下方式调用 QtConcurrent::filteredReduced():
void addToDictionary(QSet<QString> &dictionary, const QString &string) { dictionary.insert(string); } QStringList strings = ...; QFuture<QSet<QString> > dictionary = QtConcurrent::filteredReduced(strings, allLowerCase, addToDictionary);
对于filter函数返回的每个结果, reduce函数被调用一次, 并将中间值合并到结果变量中. QtConcurrent::filteredReduced()保证每次只有一个线程调用reduce, 因此不需要使用互斥锁锁定结果变量. QtConcurrent::ReduceOptions 枚举类型指明调用reduce函数顺序.如果使用QtConcurrent::UnorderedReduce(默认), 调用顺序未定义.QtConcurrent::OrderedReduce表明以容器的元素顺序调用reduce函数.
Additional API Features
使用迭代器代替容器
上述的每个函数都有一个对应的迭代器函数, 使用迭代器范围代替容器. 使用它们的方式与容器参数一样:
QStringList strings = ...; QFuture<QString> lowerCaseStrings = QtConcurrent::filtered(strings.constBegin(), strings.constEnd(), allLowerCase); // filter in-place only works on non-const iterators QFuture<void> future = QtConcurrent::filter(strings.begin(), strings.end(), allLowerCase); QFuture<QSet<QString> > dictionary = QtConcurrent::filteredReduced(strings.constBegin(), strings.constEnd(), allLowerCase, addToDictionary);
使用成员函数
QtConcurrent::filter(), QtConcurrent::filtered(), QtConcurrent::filteredReduced() 接受成员函数的指针. 这个成员函数的类型必须与容器元素类型一致:
// keep only images with an alpha channel QList<QImage> images = ...; QFuture<void> alphaImages = QtConcurrent::filter(images, &QImage::hasAlphaChannel); // retrieve gray scale images QList<QImage> images = ...; QFuture<QImage> grayscaleImages = QtConcurrent::filtered(images, &QImage::isGrayscale); // create a set of all printable characters QList<QChar> characters = ...; QFuture<QSet<QChar> > set = QtConcurrent::filteredReduced(characters, &QChar::isPrint, &QSet<QChar>::insert);
注意: 使用QtConcurrent::filteredReduced()时, 你可以自由混合使用普通函数和成员函数:
// can mix normal functions and member functions with QtConcurrent::filteredReduced() // create a dictionary of all lower cased strings extern bool allLowerCase(const QString &string); QStringList strings = ...; QFuture<QSet<int> > averageWordLength = QtConcurrent::filteredReduced(strings, allLowerCase, QSet<QString>::insert); // create a collage of all gray scale images extern void addToCollage(QImage &collage, const QImage &grayscaleImage); QList<QImage> images = ...; QFuture<QImage> collage = QtConcurrent::filteredReduced(images, &QImage::isGrayscale, addToCollage);
使用函数对象
QtConcurrent::filter(), QtConcurrent::filtered(), QtConcurrent::filteredReduced() 接受函数对象, 这些函数对象用于为函数调用增加状态记录. result_type 必须通过 typedef 定义为函数的返回类型:
struct StartsWith { StartsWith(const QString &string) : m_string(string) { } typedef bool result_type; bool operator()(const QString &testString) { return testString.startsWith(m_string); } QString m_string; }; QList<QString> strings = ...; QFuture<QString> fooString = QtConcurrent::filtered(images, StartsWith(QLatin1String("Foo")));
使用多个参数的包装函数
如果你想使用一个包含多个参数的过滤函数, 可以使用lambda函数或 std::bind()
将其转换为包含一个参数的函数.
例如, 我们想要使用 QString::contains()作为过滤函数:
bool QString::contains(const QRegularExpression ®exp) const;
QString::contains() 函数接受2个参数 (包括 "this" 指针), 不能直接作为QtConcurrent::filtered() 的过滤函数, 因为 QtConcurrent::filtered() 只接受一个参数的函数. 想要使用 QString::contains() 作为 QtConcurrent::filtered()的过滤函数, 我们必须为参数 regexp 提供默认值:
QStringList strings = ...; QFuture<QString> future = QtConcurrent::filtered(list, [](const QString &str) { return str.contains(QRegularExpression("^\\S+$")); // matches strings without whitespace });