使用constexpr索引的omp for循环

3
假设我有一个依赖于非类型模板参数的函数,这个参数是一个std::size_t类型的值,可以取值0到N-1,其中N在编译时已知。 可以使用std::sequence或模板递归来遍历所有值。例如:
#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 的通用代码很感兴趣。

1
我不确定你在问什么,但是你可以把所有的函数存储到数组中,在omp循环中调用它们,这样行不行?https://godbolt.org/z/f7vbPMeqE - Dmitry
1
我不确定你是否在问那个问题,但是你可以把所有的函数存储到数组中,在omp循环中调用它们,这样行吗? https://godbolt.org/z/f7vbPMeqE - Dmitry
1个回答

4
使用constexpr索引的omp for循环。
你可以将f更改为接受I作为参数,因为你的for循环中的i不是constexpr,不能在需要它的地方使用。
void f(std::size_t I) {
}

另一个选择是不使用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

一个替代方案是直接从`loop_f`中使用标准(自C++17起)的执行策略在`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(); });
}

这将使用Intel® oneAPI Threading Building Blocks或者您的实现所使用的后端。

第一个解决方案不可行(实际代码中的f需要在多个地方使用constexpr I)。第二个解决方案实际上是一个很好的建议(尽管可能Intel TBB比std::threads表现更好,但这是另一个方面)。谢谢! - francesco
第一个解决方案不可行(实际代码中f需要在多个地方使用constexpr I)。第二个解决方案实际上是一个很好的建议(尽管可能英特尔TBB比std::threads表现更好,但这是另一个方面)。谢谢! - francesco
第一个解决方案不可行(实际代码中f需要在多个地方使用constexpr I)。第二个解决方案实际上是一个很好的建议(尽管可能Intel TBB比std::threads表现更好,但这是另一个方面)。谢谢! - undefined
@francesco 不客气!我没有直接使用TBB,只是在使用标准算法中间接地使用了“执行策略”。我添加了一个使用这些策略的替代解决方案。 - Ted Lyngmo
@francesco 不客气!我没有直接使用TBB工具,只是在使用标准算法时间接地使用了“执行策略(_execution policies_)”。我增加了一个使用这些策略的替代解决方案。 - Ted Lyngmo

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接