英文:
omp for loop for constexpr indexes
问题
假设我有一个依赖于一个非类型模板参数的函数,一个```std::size_t```,它可以取值```0,...,N-1```,其中```N```在编译时已知。
可以使用```std::sequence```或模板递归来迭代所有值。例如:
```cpp
#include <utility>
template <std::size_t I>
void f() {
//...
}
template <std::size_t... I>
void loop_f_impl(std::index_sequence<I...>) {
(f<I>(),...);
}
template <std::size_t N>
void loop_f() {
loop_f_impl(std::make_index_sequence<N>{});
}
int main() {
constexpr std::size_t N = 4;
loop_f<N>();
}
我如何将“展开的循环”转换为可以使用openmp并行化的标准for循环?类似于以下代码(显然不能编译...)
#pragma omp for
for (std::size_t i = 0; i < N; ++i)
f<i>();
显然,例如,如果N=3,我可以用以下方式实现:
#pragma omp for
for (std::size_t i = 0; i < N; ++i)
switch (i) {
case 1:
f<1>();
break;
case 2:
f<2>();
break;
case 3:
f<3>();
break;
}
然而,我对一个适用于每个N
的通用代码感兴趣。
英文:
Suppose I have a function depending on a nontype template argument, an std::size_t
, which can take value 0,...,N-1
, with N
known at compile time.
An iteration over all values can be done with a std::sequence
or with a template recursion. E.g.:
#include <utility>
template <std::size_t I>
void f() {
//...
}
template <std::size_t... I>
void loop_f_impl(std::index_sequence<I...>) {
(f<I>(),...);
}
template <std::size_t N>
void loop_f() {
loop_f_impl(std::make_index_sequence<N>{});
}
int main() {
constexpr std::size_t N = 4;
loop_f<N>();
}
How can I convert the "unrolled loop" to a standard for loop that I can parallelize with openmp? Something like that (which obviously does not compile...)
#pragma omp for
for (std::size_t i = 0; i < N; ++i)
f<i>();
Clearly, if, say, N=3, I could implement that with
#pragma omp for
for (std::size_t i = 0; i < N; ++i)
switch (i) {
case 1:
f<1>();
break;
case 2:
f<2>();
break;
case 3:
f<3>();
break;
}
I am interested however in a generic code that works for every N
.
答案1
得分: 4
omp for loop for
constexpr
indexes您可以将
f
修改为接受I
作为参数,因为您的for
循环中的i
不是constexpr
,不能在需要constexpr
的地方使用。void f(std::size_t I) { }
Another option, without using omp, could be to launch all
f<I...>()
s asynchronously:另一种选择,不使用 omp,是将所有的
f<I...>()
异步启动:#include <future> #include <tuple> template <std::size_t... I> void loop_f_impl(std::index_sequence<I...>) { std::tuple all{ std::async(std::launch::async, f<I>)... }; } // here all futures stored in the `tuple` wait until done
An alternative could be to use one of the standard (since C++17) Execution Policies directly from
loop_f
in astd::for_each
. Example:另一种选择是直接从
loop_f
中使用标准的(自 C++17 起)Execution Policies 中的一个,在std::for_each
中使用。示例:#include <algorithm> #include <array> #include <execution> template <std::size_t N> void loop_f() { // C++20 lambda template: constexpr auto funcs = []<std::size_t... Is>(std::index_sequence<Is...>) { return std::array{f<Is>...}; }(std::make_index_sequence<N>{}); std::for_each(std::execution::par_unseq, funcs.begin(), funcs.end(), [](auto func) { func(); }); }
This will make use of Intel® oneAPI Threading Building Blocks or whatever your implementation uses as a backend.
英文:
> omp for loop for constexpr
indexes
You could change f
to take I
as an argument instead since i
in your for
loop is not constexpr
and can't be used where one is needed.
void f(std::size_t I) {
}
Another option, without using omp, could be to launch all f<I...>()
s asynchronously:
#include <future>
#include <tuple>
template <std::size_t... I>
void loop_f_impl(std::index_sequence<I...>) {
std::tuple all{ std::async(std::launch::async, f<I>)... };
} // here all futures stored in the `tuple` wait until done
An alternative could be to use one of the standard (since C++17) Execution Policies directly from loop_f
in a std::for_each
. Example:
#include <algorithm>
#include <array>
#include <execution>
template <std::size_t N>
void loop_f() {
// C++20 lambda template:
constexpr auto funcs = []<std::size_t... Is>(std::index_sequence<Is...>) {
return std::array{f<Is>...};
}(std::make_index_sequence<N>{});
std::for_each(std::execution::par_unseq, funcs.begin(), funcs.end(),
[](auto func) { func(); });
}
This will make use of Intel® oneAPI Threading Building Blocks or whatever your implementation uses as a backend.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论