Qt在其QtConcurrent命名空间中为我们提供了编写多线程程序的高级API,使用这个API可以使我们在不使用低级的线程元素,如互斥锁,读写锁,条件变量或者信号量的情况下编写出搞笑的多线程程序。并且,使用QtConcurrent编写的程序能够自动地根据当前可以使用的处理器核心数调整实际使用的线程数目。这就意味着我们目前所写的程序即使将来的多核心机器上也能正常运行,并有很好的伸缩性。
QtConcurrent命名空间中包括了用于并行处理的函数式编程API,其中有用于共享内存系统的MapReduce 和 FilterReduce,和用于在GUI程序中管理异步计算的相关类。其中,管理异步计算的几个类,我们在前面已经说过了,即QFuture,QFutureIterator,QFutureWatcher,QFutureSynchronizer。今天,我们主要来看一下MapReduce和FilterReduce方法。
MapReduce相关方法包括:
QtConcurrent::map():这个函数会将作为参数传入的函数应用到容器中的每一项,对这些项进行就地修改。
QtConcurrent::mapped():功能类似于map(),只不过它不是在原来的容器中就地修改,而是将修改后的元素放到一个新的容器中返回。
QtConcurrent::mappedReduce():功能类似于mapped(),只不过它会将修改过的每一项再传入另一个Reduce函数进行简化,将多个结果按某种要求简化成一个。
FilterReduce相关方法包括:
QtConcurrent::filter():从容器中删除那些满足某个过来条件的项。
QtConcurrent::filtered():功能类似于filter(),只不过它会返回一个包含剩余元素的容器。
QtConcurrent::filteredReduced():功能类似于filtered(),只不过那些剩余的元素会被进一步传入一个Reduce() 函数,进行简化。
QtConcurrent命名空间中组合一类函数,就是我们之间讲过的run() 函数。
下面,我们分别通过实例还看一下这些函数的使用方法。先来看Map类方法,代码如下:
#include
#include
#include
#include
#include
void testMap(int& num)
{
num += 1;
}
int testMap2(const int& num)
{
return num + 1;
}
void testReduce(int& result, const int& item)
{
result = item > result ? item : result;
}
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
QVector vec;
qsrand(QTime(0,0,0).secsTo(QTime::currentTime()));
for(int i = 1; i <= 10; i++)
{
vec.push_back(qrand() % 100);
}
qDebug() << "origin: " << vec;
//Map
QFuture f = QtConcurrent::map(vec, testMap);
f.waitForFinished();
qDebug() << "after map: " << vec;
QFuture r = QtConcurrent::mappedReduced(vec, testMap2, testReduce);
qDebug() << "max: " << r.result();
return a.exec();
}
首先,在上面的代码中,我们声明了两个map类函数。testMap()用于QtConcurrent::map(),对容器中的每一项进行就地修改;testMap2()用于QtConcurrent::MappedReduced(),将进行过map的那些元素简化成一个,在此我们是求map后容器中的最大值。注意testMap()和testMap2()的区别。
上面的代码实现的功能很简单。先产生10个随机数存入vector,然后对该vector应用testMap()方法,将容器中的每一项加1,输出加1后的结果;然后我们再对加1处理过的容器应用testMap2()和testReduce(),其中testMap2()会对容器中的每一项再加1,然后将结果传入testReduce()方法,该方法找出当前容器中的最大值。运行结果如下:
下面,我们再来简单看下Filter类函数,还是先上代码:
#include
#include
#include
#include
#include
void testReduce(int& result, const int& item)
{
result = item > result ? item : result;
}
bool testFilter(const int& item)
{
return item >= 50;
}
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
QVector vec;
qsrand(QTime(0,0,0).secsTo(QTime::currentTime()));
for(int i = 1; i <= 10; i++)
{
vec.push_back(qrand() % 100);
}
qDebug() << "origin: " << vec;
//Filter
QFuture f = QtConcurrent::filter(vec, testFilter);
f.waitForFinished();
qDebug() << "after filter: " << vec;
QFuture r = QtConcurrent::filteredReduced(vec, testFilter, testReduce);
qDebug() << "max: " << r.result();
return a.exec();
}
当然,这里只是简单的演示一下该命名空间中常用函数的使用方法。大家主要要注意MapFunction、FilterFunction、ReduceFunction的声明,形式不能错。
另外,上面演示的这些函数都是QtConcurrent命名空间中的非阻塞函数。其实,在该命名空间中还提供了一系列的阻塞函数。声明信息如下:
void blockingFilter(Sequence &sequence, FilterFunction filterFunction)
Sequence blockingFiltered(const Sequence &sequence, FilterFunction filterFunction)
Sequence blockingFiltered(ConstIterator begin, ConstIterator end, FilterFunction filterFunction)
T blockingFilteredReduced(const Sequence &sequence, FilterFunction filterFunction, ReduceFunction reduceFunction, QtConcurrent::ReduceOptions reduceOptions = UnorderedReduce | SequentialReduce)
T blockingFilteredReduced(ConstIterator begin, ConstIterator end, FilterFunction filterFunction, ReduceFunction reduceFunction, QtConcurrent::ReduceOptions reduceOptions = UnorderedReduce | SequentialReduce)
void blockingMap(Sequence &sequence, MapFunction function)
void blockingMap(Iterator begin, Iterator end, MapFunction function)
T blockingMapped(const Sequence &sequence, MapFunction function)
T blockingMapped(ConstIterator begin, ConstIterator end, MapFunction function)
T blockingMappedReduced(const Sequence &sequence, MapFunction mapFunction, ReduceFunction reduceFunction, QtConcurrent::ReduceOptions reduceOptions = UnorderedReduce | SequentialReduce)
T blockingMappedReduced(ConstIterator begin, ConstIterator end, MapFunction mapFunction, ReduceFunction reduceFunction, QtConcurrent::ReduceOptions reduceOptions = UnorderedReduce | SequentialReduce)
这些函数的使用方式和上面演示的非阻塞函数类似,在此就不一一演示了,大家可以自行测试,或使用上面我给出的例子进行测试。