如何在循环中使用所有核心?

时间:2018-03-14 15:13:08

标签: c++ multithreading c++11 c++14 c++17

有一个循环。

for (int i = 0; i < n; ++i) {
    //...
    v[i] = o.f(i);
    //...
}

每个v[i] = o.f(i)都与所有其他v[i] = o.f(i)无关 n可以是任何值,也可以不是核心数的倍数。使用所有核心执行此操作的最简单方法是什么?

2 个答案:

答案 0 :(得分:6)

<algorithm>中的算法的ExecutionPolicy重载就是为此目的而存在的。 std::transform将一个函数应用于源范围的每个元素以分配给目标范围。

v.begin()是可接受的目的地,只要v的大小合适即可。

然后我们需要一个迭代器,它将值v[i]作为我们的源,所以boost::counting_iterator<int>

最后,我们需要[0, n)Callable应用于我们的值,因此我们在lambda中捕获o.f

o

如果#include <algorithm> #include <execution> #include <boost/iterator/counting_iterator.hpp> // assert(v.size() >= n) std::transform(std::execution::par, boost::counting_iterator<int>(0), boost::counting_iterator<int>(n), v.begin(), [&o](int i){ return o.f(i); }); 未执行任何&#34;矢量化不安全操作&#34;,您可以使用std::execution::par_unseq可以在其上交错线程(即展开循环并使用SIMD指令)

答案 1 :(得分:4)

在现有编译器的土地上,并且记住M / S甚至无法获得适合C ++ 11的东西,更别关注C ++ 17/20,C ++ 11答案如下:

typedef v.value_type R;
std::vector< std::future<R> > fut(n);
for (int i=0; i<n; i++)
    fut[i] = std::async(std::launch::async, O::f, o, i);
for (auto& f : fut)
    v.push_back(f.get());
@arne建议我们可以通过考虑处理器数量(P)来限制任务数量来做得更好,这是正确的,尽管上面的代码可以清楚地说明你是否真的会受益于多线程方法f。鉴于我们只想同时启动X作业,其中X是> 0。 P,&lt; 3 * P取决于工作复杂性的变化(注意我依赖于签名索引):

typedef v.value_type R;
std::vector< std::future<R> > fut(n);
for (ssize_t i=0, j=-X; j<n; i++,j++)
{
    if (i<n)    fut[i] = std::async(std::launch::async, O::f, o, i);
    if (j>=0)   v.push_back(fut[j].get());
}

我并不是说上面的代码“很棒”,但是如果这些作业足够复杂,我们需要多线程,那么多次循环的成本并不值得注意。你会注意到,如果X&gt; n循环将在中间旋转几次,但会产生正确的结果: - )