使用 std::for_each 和 std::views::iota 的并行 for 循环
我想使用 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
我在这里发现了类似的问题:使用范围::view:: iota 并行算法 ,我实现了那里提供的解决方案:
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.
有人知道这个问题是否有解决方案?
I want to set up an easy workaround for parallelized index-based for-loops using std::views
.
For running in sequence the code looks like this:
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;
}
This works fine. I am using the standard version of std::for_each()
, not the one in the ranges
namespace, because those don't have the execution policies. Now the parallel version. Only difference:
for_each(execution::par, r.begin(), r.end(), [&](int i) {v[i] = distr(eng); });
MSVC gives an error:
error C2338: Parallel algorithms require forward iterators or stronger
I found a similar issue here: Using ranges::view::iota in parallel algorithms and I implemented the solution offered there:
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;
However, I am still facing the error
error C2338: Parallel algorithms require forward iterators or stronger.
Does someone know whether there is a solution to this issue?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
views::iota
迭代器的operator*()
返回类型不是引用类型,而是值类型,这使得它不是 C++17 中的前向迭代器而是输入迭代器。由于 C++17 并行算法需要前向迭代器,因此您无法将其应用于views::iota
。已经有一篇论文 p2408r4 解决这个问题,因此在标准被采用之前没有简单的解决方案。
The return type of
operator*()
ofviews::iota
's iterator is not a reference type but a value type, which makes it not a forward iterator but an input iterator in C++17. Since the C++17 parallel algorithm requires forward iterators, you cannot apply it toviews::iota
.There is already a paper p2408r4 addressing this issue, so there is no simple solution in the standard until it is adopted.
p2408现已在C++23中采用。在 MSVC 19.34 (VS 17.4) 或更高版本中,如果打开
/std:c++latest
,代码将会编译(/std:c++20
也可以工作) )。 <一href="https://godbolt.org/#g:!((g:!((g:!((h:codeEditor,i:(文件名:%271%27,fontScale:14,fontUsePx:%270% 27,j:1,lang:c%2B%2B,选择:(endColumn:26,endLineNumber:15,positionColumn:26,positionLineNumber:15,sel ectionStartColumn:26、selectionStartLineNumber:15、startColumn:26、startLineNumber:15)、来源:%27%23include%3Crandom%3E%0A%23include%3Ciostream%3E%0A%23include%3Cranges%3E%0A%23include%3Cexecution% 3E%0A%0Aint+ma in()+%7B%0A%09using+命名空间+std%3B%0A%0A%09random_device+rd%3B%0A%09default_random_engine+eng(rd())%3 B%0A%09uniform_int_distribution%3Cint%3E+distr(0,+100)%3B%0A%0A%09auto+r+%3D+范围::视图::iota(0,+10)% 3B%0A%09向量%3Cdouble%3E+v(10,+1)%3B%0A%09for_each(执行::par,r.begin(),+r.end(),+%5B%26%5D(整数+i) +%7Bv%5Bi%5D+%3D+distr(eng)%3B+%7D)%3B%0A%09for+(自动%26%26+i+:+v)+cout+%3C%3C+i+%3C%3C+% 22+%22%3B+cout+ %3C%3C+endl%3B%0A%7D%27),l:%275%27,n:%270%27,o:%27C%2B%2B+源+%231%27,t:%270% 27)),k:50,l:%274%27,n:% 270%27,o:%27%27,s:0,t:%270%27),(g:!((h:编译器,i:(编译器:vcpp_v19_34_x64,deviceViewOpen:%271%27,过滤器rs:(b:%270%27,二进制:%271%27,binaryObject:%271%27,仅注释:%270%27,demangle:%270%27,指令:%270%2 7、执行:%271%27、英特尔:%270%27、库代码:%270%27、修剪:%271%27)、flagsViewOpen:%271%27、fontScale:14、fon tUsePx:%270%27,j:1,lang:c%2B%2B,库:!(),选项:%27/std:c%2B%2Blatest%27,选择:(endColumn:1,endLineNumber:1 ,positionColumn:1,positionLineNumber:1,selectionStartColumn:1,selectionStartLineNumber:1,startCo流:1,起始行号:1),来源:1),l:%275%27,n:%270%27,o:%27+x64+msvc+v19.34+(编辑器+%231)%27,t :%270%27 )),k:50,l:%274%27,n:%270%27,o:%27%27,s:0,t:%270%27)),l:%272%27,n: %270%27,o:%27%27,t:%270%27)),版本:4" rel="nofollow noreferrer">示例p2408 is adopted in C++23 now. In MSVC 19.34 (VS 17.4) or later, the code will compile if you turn on
/std:c++latest
(/std:c++20
will also work). EXAMPLE也许只是一个小更新。
正如所指出的,该代码不能使用 MSVC 进行编译。
然而,该代码确实使用 g++-11 进行编译,因为 libstd++ 不对迭代器类别进行任何预先检查。
但是,无论执行策略如何,代码始终串行运行。
重要提示:以下只是我的建议,如有错误请指正。
如果您仍然想实现一个简单的基于并行索引的
for
循环,您可以使用 STL 容器而不是视图:我们现在不再使用视图,而是将索引存储在
中矢量
。这当然会带来内存和运行时开销,因为必须为容器分配内存并且必须用索引填充容器。实际运行的函数可能如下所示:
Maybe just a small update.
As was pointed out, the code does not compile with MSVC.
The code does, however, compile with g++-11 since libstd++ does not do any up-front checking of the iterator category.
However, the code runs always in serial, irrespective of the execution policy.
Important: The following is just my suggestion, please correct me if I am wrong.
If you still want to implement an easy parallelized index-based
for
loop, you can make use of STL containers rather than views:Instead of having a view, we now just store the indices in a
vector<int>
. This of course comes with a memory and runtime overhead since memory for the container must be allocated and the container must be filled with the indices.The function in action could look like this: