std::asyncによる並列for_each
C++ではOpenMPよりも、std algorithmが並列に動いた方が便利だよね。ということで作りました。元ネタはhttps://twitter.com/cpp_akira/status/16195866927です。
#ifdef _OPENMP inline size_t concurrency_omp() { size_t n; #pragma omp parallel { n = omp_get_num_threads(); } return n; } #endif inline size_t concurrency() { #ifdef _OPENMP static size_t const n{concurrency_omp()}; #else // g++ 4.5's hardware_concurrency() always returns zero :-( auto const n = std::thread::hardware_concurrency(); #endif return std::max<decltype(n)>(1, n); } template <class It, class F> void for_each(It begin, It end, F&& f) { auto const total = std::distance(begin, end); auto const c = (size_t)total < concurrency() ? 1 : concurrency(); auto const num = total / c; std::vector<std::future<void> > futures; futures.reserve(c); for (size_t i = 0; i < c; ++i) { futures.push_back(std::async([&, i] { std::for_each(begin + num * i, begin + num * (i + 1), f); })); } std::for_each(begin + num * c, end, f); std::for_each(futures.begin(), futures.end(), [] (std::future<void>& f) { f.wait(); }); }
割と適当です。Itはrandom access iteratorでないとエラーになります*1。g++のstd::thread::hardware_concurrencyは常に0が帰ってくるので、OpenMPが使える時はそっちで並列度を取ってます。static変数の初期化はMT-safeなので、concurrencyを同時に呼んでも大丈夫だよね…?
Mac環境だと