首页 > 解决方案 > 如何在系统上使用并行 std::for_each不见了?

问题描述

这个 C++17 片段在较新版本的 G++ 中运行良好

std::for_each(std::execution::par_unseq, container.begin(), container.end(), [&](const auto& element) {
    // do something with element... or don't. whatever.
});

例如,当您尝试将该代码移植到具有 G++ 8.3.0(截至 2020 年 12 月)的当前 Debian(Stable)发行版时,您会发现自己正在阅读以下错误消息:

fatal error: execution: File not found
     #include <execution>
              ^~~~~~~~~~~

一个明显的依赖于__has_include涉及宏的解决方案是:

#if __has_include(<execution>)
    #include <execution>
    #define PAR_UNSEQ std::execution::par_unseq,
#else
    #define PAR_UNSEQ
#endif

std::for_each(PAR_UNSEQ container.begin(), container.end(), [&](const auto& element) {
    // do something with element... or don't. whatever.
});

这编译得很好,但在我看来有两个主要问题:

那么有没有更好的方法呢?

或者,如果没有,至少有一个宏解决方案实际上是并行的for_each

标签: c++for-loopc++17

解决方案


<execution>是在 gcc 9(我认为是 9.1)中添加的,但您可以直接使用底层库Intel® oneAPI 线程构建块tbb简称。这有点麻烦,但是如果您链接到下面的内容,则可以在 gcc 8.3 中使用-ltbb(即使在包含的较新 gcc 版本中,您也需要链接<execution>)。我的示例使用tbb::parallel_for的是 gcc:sstd::for_each最有可能使用的。

我认为它解决了最重要的部分,那就是它在没有<execution>标头的系统上是并行的。

#if __has_include(<execution>)
    #include <execution>
#else
    #include "tbb/tbb.h"

    // define a support class for using with tbb::paralell_for
    template<typename C, typename Func>
    class ApplyFunc {
    public:
        ApplyFunc(const C& container, Func func) : c(container), f(func) {}

        // the function that will be called for each block
        void operator()(const tbb::blocked_range<size_t>& r) const {
            for(size_t i = r.begin(); i != r.end(); ++i) 
                f(c[i]); // the function you'd like to apply to each element
        }

    private:
        const C& c;
        Func f;
    };
#endif

// A function to call std::for_each or the tbb version
template<typename C, typename Func>
decltype(auto) myfor_each(const C& container, Func func) {
    #if __has_include(<execution>)
        std::for_each(std::execution::par, container.begin(), container.end(), func);
    #else
        tbb::parallel_for(tbb::blocked_range<size_t>(0, container.size()),
                          ApplyFunc(container, func));
    #endif
}

int main() {
    // example usage
    std::vector<int> container;
    myfor_each(container, [](auto& e) { do something eith e });
}

推荐阅读