TaskCpp简介
TaskCpp是c++11开发的一个跨平台的并行task库,它的设计思路来源于微软的并行计算库ppl和intel的并行计算库tbb,关于ppl和tbb我在前面有介绍。既然已经有了这两个大公司开发的并行计算库,我为什么还要开发自己的并行计算库。有两个原因:
ppl只能在windows上用不能跨平台,tbb能跨平台,但是受限于原始设计,tbb的task比较弱没有ppl的强大,所以他们不能完全满足我的要求;
我觉得可以用c++11可以开发出一个轻量级的好用的并行task库。
TaskCpp在接口设计上尽量和ppl保持一致,因为我觉得ppl的接口很好很强大。因此,TaskCpp的接口用法和语义和ppl基本是一致的。因为TaskCpp是一个轻量级的task库,总共也不过三百多行代码,本着简单够用的原则,只提供了一些和ppl类似的常用用法, 有些不常用的特性不考虑支持。比如,不支持任务的取消,因为加入任务的取消会导致增加很多复杂性,而实际中用得比较少,所以不考虑支持,够用就好。
支持的平台
需要支持c++11的编译器,建议编译器:
linux: GCC4.7+
windows: vs2012 nov ctp+, 最好是vs2013
库的使用
使用TaskCpp仅仅需要包含头文件即可,在程序中使用只需要包含#include
TaskCpp的功能
TaskCpp提供一下功能:
并行任务:一种并行执行若干工作任务的机制。
基本的异步任务
延续的任务
组合任务
WhenAll
WhenAny
任务组
并行算法:并行作用于数据集合的泛型算法。
ParallelForeach算法
ParallelInvoke算法
ParallelReduce算法
TaskCpp用法介绍
并行任务
基本的异步任务Task
Task会创建一个异步操作,这个异步操作发起方式是延迟加载方式发起的,即在调用Task的Wait或者Get时才真正发起异步操作。Task可以通过std::function或者lambda表达式去创建,不支持直接原生函数创建,如果要用原生函数需要先通过lambda或者std::function包装一下。Task的Wait接口只是等待异步操作结束。Task的Get接口接收参数并等待异步操作结束并返回结果。PPL中的get接口是不能接收参数的,TaskCpp的Get接口是可以接受任意参数的,更灵活一点,算是较PPL的一个小优点吧。下面是Task的基本用法:
View Code
组合任务--WhenAll
WhenAll保证一个任务集合中所有的任务完成。WhenAll函数会生成一个任务,该任务可在完成一组任务之后完成。 此函数可返回一个std::vector 对象,该对象包含集合中每个任务的结果。 以下基本示例使用WhenAll创建表示完成其他三个任务的任务。下面是WhenAll的基本用法:
View Code
注意:WhenAll是非阻塞的,它只是创建一个任务,在Wait或Get时才发起异步操作。传递给WhenAll的任务必须是统一的。 换言之,它们必须都返回相同类型。
组合任务--WhenAny
WhenAny在任务集合中任意一个任务结束之后就返回。函数会生成一个任务,该任务可在完成一组任务的第一个任务之后完成。 此函数可返回一个 std::pair 对象,该对象包含已完成任务的结果和集合中任务的索引。下面是WhenAny的基本用法:
View Code
注意:WhenAny是非阻塞的,它只是创建一个任务,在Wait或Get时才发起异步操作。传递给WhenAny的任务必须是统一的。 换言之,它们必须都返回相同类型。
任务组--TaskGroup
TaskGroup可以并行的处理一组任务,TaskGroup可以接受多个task或者function,TaskGroup的Wait等待所有任务完成。下面是TaskGroup的基本用法:
View Code
PPL的task_group的任务只能是void()形式的,TaskCpp允许一些简单类型的任务如int()、double()、string()等,其实任务的返回类型没有实际意义,因为Wait没有返回值,这里支持多种返回类型的任务只不过是为了减少一点限制,用起来稍微方便一点罢了。PPL加入任务只能一个一个Run,要加入多个任务时有点繁琐,TaskCpp可以一次Run多个任务,比PPL要方便一些。这两点算是较PPL的两个小优点吧。
并行算法
ParallelForeach算法
ParallelForeach算法与 STL std::for_each 算法类似,只是 parallel_for_each 算法并发执行任务。用法比较简单:
View Code
ParallelInvoke算法
ParallelInvoke算法并行执行一组任务。 在完成所有任务之前,此算法不会返回。 当您需要同时执行多个独立的任务时,此算法很有用。ParallelInvoke和TaskGroup的作用是一样的。用法比较简单:
void TestParaInvoke()
{
auto f = []{cout << "1" << endl; return 1; };
ParallelInvoke(f, []{cout << "2" << endl; });
}
ParallelReduce算法
ParallelReduce算法在实际应用中比较常用,有点类似于map-reduce,可以并行的对一个集合进行reduce操作。ParallelReduce的用法稍微复杂一点,它的原型:
ParallelReduce(range,init, reduceFunc);
ParallelReduce(range,init, rangeFunc, reduceFunc);
第一个参数是集合,第二个参数是算法的初始值,第三个参数rangeFunc是一个声称中间结果的函数,第四个参数是中间结果的汇聚函数。如果调用ParallelReduce(range,init, reduceFunc),则表示rangeFunc和reduceFunc是一个函数。