2.1.1 并行版的for循环
现在,让我们来看一段标准C++(www.cppentry.com)版的for循环代码:
- vector<double> results = ...
- int workload = ...
- size_t n = results.size();
- for (size_t i = 0; i < n; ++i)
- {
- results[i] = DoWork(i, workLoad);
- }
接下来,为了体现出多核的性能优势,我们改用parallel_for函数来代替for关键字,并用lambda表达式(lambda expression)注1来替代原来的循环体。
如果你想使用并行循环,不要忘记循环各步骤间需要彼此独立,确保它们之间的通信不以写共享变量的方式来实现。
- vector<double> results = ...
- int workload = ...
- size_t n = results.size();
-
- parallel_for(0u, n,[&results, workLoad](size_t i)
- {
- results[i] = DoWork(i, workLoad);
- });
现在,只要条件允许,parallel_for函数就能利用多核资源来遍历上述代码中的索引区间。
在代码中,形如[captured variables] (args){body}的语句实质上是一个lambda表达式。在继续深入阅读之前,你或许应该去复习一下C++(www.cppentry.com)中关于 lambda表达式的语法内容。
另外,parallel_for函数还有一系列不同的重载(overload)版本。上述示例中所调用的版本声明如下。
- template <typename _Index_type, typename _Function>
- void parallel_for(_Index_type _First,
- _Index_type _Last,
- const _Function& _Func);
在该函数中,前两个参数所表示的是该迭代的边界。第一个参数是循环的下界位;第二个参数则为循环的出界位,即上界位+1;而第三个参数则是一个作用于历次迭代的函数,迭代次数是该函数的参数之一。这意味着该循环的每次迭代操作都会调用这个函数。
关于parallel_for函数的另一个重载,我们将会在2.3节中再介绍。
和串行循环不同的是,parallel_for方法不能保证操作的顺序,即对较大索引值的操作可能排在较小索引值之前。
例子中类似于parallel_for第三参数那样的,形如[captured variables] (args) {body}的表达式,被称为lambda表达式。该表达式实质是一个能够捕获自己所在作用域中变量的函数对象。当然,_Func参数并不一定非得是lambda表达式,它也可以是一个函数指针注2(指向一个在别处声明的函数)。
如果你对lambda表达式的语法还不熟悉,可以参考2.7节中所推荐的文章。相信我,一旦你使用了lambda表达式,就会对它有一种相见恨晚的感觉。