c++ 使用std::for_each和std::views::iota并行for循环

up9lanfz  于 2023-05-20  发布在  其他
关注(0)|答案(3)|浏览(192)

我想使用std::views为并行化的基于索引的for循环设置一个简单的解决方案。
对于顺序运行,代码看起来像这样:

int main() {

    //pseudo-random numbers

    random_device rd;
    default_random_engine eng(rd());
    uniform_int_distribution<int> distr(0, 100);

    auto r = ranges::views::iota(0, 10);
    vector<double> v(10, 1);
    for_each(r.begin(), r.end(), [&](int i) {v[i] = distr(eng); });
    for (auto&& i : v) cout << i << " "; cout << endl;
}

这个很好用。我使用的是std::for_each()的标准版本,而不是ranges名称空间中的版本,因为它们没有执行策略。现在是平行版本。唯一的区别:

for_each(execution::par, r.begin(), r.end(), [&](int i) {v[i] = distr(eng); });

MSVC给出错误:

error C2338: Parallel algorithms require forward iterators or stronger

我在这里发现了一个类似的问题:Using ranges::view::iota in parallel algorithms和我实现了那里提供的解决方案:

auto r = views::iota(0) | views::take(10);
    vector<double> v(10, 1);
    auto input_range = ranges::common_view(r);

    for_each(execution::par, ranges::begin(input_range), ranges::end(input_range), [&](int i) {v[i] = distr(eng); });
    for (auto&& i : v) cout << i << " "; cout << endl;

然而,我仍然面临着错误

error C2338: Parallel algorithms require forward iterators or stronger.

有人知道这个问题是否有解决方案吗?

qhhrdooz

qhhrdooz1#

views::iota的迭代器operator*()的返回类型 * 不是 * 引用类型而是值类型,这使得它 * 不是 * 前向迭代器而是C17中的输入迭代器。由于C17并行算法需要前向迭代器,因此不能将其应用于views::iota
有人知道这个问题是否有解决方案吗?
已经有一篇论文p2408r4解决了这个问题,所以在标准中没有简单的解决方案,直到它被采用。

vu8f3i0k

vu8f3i0k2#

p2408现在被C++23采用。在MSVC 19.34(VS 17.4)或更高版本中,如果打开/std:c++latest/std:c++20也可以工作),代码将编译。示例

du7egjpx

du7egjpx3#

也许只是一个小小的更新。如前所述,代码不能用MSVC编译。然而,这段代码可以用g++-11编译,因为libstd++不对迭代器类别进行任何预先检查。但是,代码总是串行运行,而不管执行策略如何。
重要提示:以下只是我的建议,如果我错了,请纠正我。如果你仍然想实现一个简单的并行化的基于索引的for循环,你可以使用STL容器而不是视图:

template<typename Policy, typename func>
void parallel_for(Policy p, int first, int last, func f) {

    vector<int> idxs(last - first);
    iota(idxs.begin(), idxs.end(), first);
    for_each(p, begin(idxs), end(idxs), f);
}

我们现在没有视图,而是将索引存储在vector<int>中。这当然伴随着内存和运行时开销,因为必须为容器分配内存,并且必须用索引填充容器。实际的函数可能如下所示:

int fib(int i) {
    if (i <= 1)
        return i;
    return fib(i - 1) + fib(i - 2);
}

int main() {

    vector<vector<double>> mat(100, vector<double>(100, 1));

    parallel_for(execution::par, 0, mat.size(), [&mat](int i) {

        for (int j = 0; j < mat[i].size(); ++j) {
            mat[i][j] = fib(40);
        }
        });
}

相关问题