[英]STL parallel execution vs. OpenMP performance
我正在開始一個新項目,並希望並行化一些計算。 我過去使用過 OpenMP,但我知道現在可以直接並行化許多 STL 算法。 由於這兩種方法都遵循不同的范例(例如原始循環與迭代器和匿名函數),我想預先選擇一種。
一般哪個更快?
為了對此進行測試,我對以下 C++20 代碼進行了基准測試:
#include <algorithm>
#include <iostream>
#include <vector>
#include <numeric>
#include <cmath>
#include <chrono>
#include <execution>
template <class ExecutionPolicy>
int test_stl(const std::vector<double>& X, ExecutionPolicy policy) {
std::vector<double> Y(X.size());
const auto start = std::chrono::high_resolution_clock::now();
std::transform(policy, X.cbegin(), X.cend(), Y.begin(), [](double x){
volatile double y = std::sin(x);
return y;
});
const auto stop = std::chrono::high_resolution_clock::now();
auto diff = std::chrono::duration_cast<std::chrono::microseconds>(stop - start);
return diff.count();
}
int test_openmp(const std::vector<double>& X) {
std::vector<double> Y(X.size());
const auto start = std::chrono::high_resolution_clock::now();
#pragma omp parallel for
for (size_t i = 0; i < X.size(); ++i) {
volatile double y = std::sin(X[i]);
Y[i] = y;
}
const auto stop = std::chrono::high_resolution_clock::now();
auto diff = std::chrono::duration_cast<std::chrono::microseconds>(stop - start);
return diff.count();
}
int main() {
const size_t N = 10000000;
std::vector<double> data(N);
std::iota(data.begin(), data.end(), 1);
std::cout << "OpenMP: " << test_openmp(data) << std::endl;
std::cout << "STL seq: " << test_stl(data, std::execution::seq) << std::endl;
std::cout << "STL par: " << test_stl(data, std::execution::par) << std::endl;
std::cout << "STL par_unseq: " << test_stl(data, std::execution::par_unseq) << std::endl;
std::cout << "STL unseq: " << test_stl(data, std::execution::unseq) << std::endl;
return 0;
}
在我的機器上使用 GCC 10.3.0 (MSYS2) 編譯,OpenMP 代碼的運行速度始終快 10 倍:
OpenMP: 54719
STL seq: 628451
STL par: 638454
STL par_unseq: 494143
STL unseq: 506647
對於功能等效的代碼,OpenMP 通常(啟發式)更快嗎? 考慮到目前的 state 發展,這可能會在未來改變嗎?
編輯:
我正在使用以下CMakeLists.txt
構建此基准:
cmake_minimum_required(VERSION 3.19)
add_executable(TEST main.cpp)
target_compile_features(TEST PRIVATE cxx_std_20)
set_target_properties(TEST PROPERTIES CXX_EXTENSIONS OFF)
find_package(OpenMP)
target_link_libraries(TEST PUBLIC OpenMP::OpenMP_CXX)
然后我用 Windows Powershell 命令編譯它:
cmake .. -G "MinGW Makefiles"
mingw32-make
./TEST.exe
我已經在我的 windows 11 機器上使用 MSVC 測試了你的代碼(只是在 openmp 實現中將 size_t 更改為 int),因為我認為讓 almos all stl 以相同的性能並行是非常奇怪的...... seq
執行策略不完全執行並行性......並且在你的測試中它的表現非常接近其他執行策略......
所以,我已經編譯了這個:
cl.exe /Zi /EHsc /nologo /std:c++latest /O2 /openmp /Fe: .\openmp-vs-exec-policy.exe .\openmp-vs-exec-policy.cpp
我的結果是:
.\openmp-vs-exec-policy.exe
OpenMP: 14089
STL seq: 99299
STL par: 10659
STL par_unseq: 9811
STL unseq: 68051
在我的另一個測試中,stl 幾乎總是比 openmp 表現更好......
所以,我的猜測是你正在使用的 stl 沒有很好地實現或者 GCC 對於 windows 沒有很好地編譯 stl ...
[編輯]
我一直在尋找 g++ 實現 STL 並行性,發現它只有在安裝了 libtbb 時才有效。
就像 OpenMP 只有在使用-fopenmp
編譯時才有效,如果它沒有傳遞給編譯器,一切都會回落到順序,STL 如果你沒有安裝 libtbb,執行策略的實現會回落到順序默認為 g++。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.