[英]Why std::for_each is faster than __gnu_parallel::for_each
我試圖理解為什么在以下示例中在單線程上運行的std::for_each
比__gnu_parallel::for_each
快~3
倍:
Time =0.478101 milliseconds
與
Time =0.166421 milliseconds
這是我用來基准測試的代碼:
#include <iostream>
#include <chrono>
#include <parallel/algorithm>
//The struct I'm using for timming
struct TimerAvrg
{
std::vector<double> times;
size_t curr=0,n;
std::chrono::high_resolution_clock::time_point begin,end;
TimerAvrg(int _n=30)
{
n=_n;
times.reserve(n);
}
inline void start()
{
begin= std::chrono::high_resolution_clock::now();
}
inline void stop()
{
end= std::chrono::high_resolution_clock::now();
double duration=double(std::chrono::duration_cast<std::chrono::microseconds>(end-begin).count())*1e-6;
if ( times.size()<n)
times.push_back(duration);
else{
times[curr]=duration;
curr++;
if (curr>=times.size()) curr=0;}
}
double getAvrg()
{
double sum=0;
for(auto t:times)
sum+=t;
return sum/double(times.size());
}
};
int main( int argc, char** argv )
{
float sum=0;
for(int alpha = 0; alpha <5000; alpha++)
{
TimerAvrg Fps;
Fps.start();
std::vector<float> v(1000000);
std::for_each(v.begin(), v.end(),[](auto v){ v=0;});
Fps.stop();
sum = sum + Fps.getAvrg()*1000;
}
std::cout << "\rTime =" << sum/5000<< " milliseconds" << std::endl;
return 0;
}
這是我的配置:
gcc version 7.3.0 (Ubuntu 7.3.0-21ubuntu1~16.04)
Intel® Core™ i7-7600U CPU @ 2.80GHz × 4
htop
檢查程序是否在單線程或多線程中運行
g++ -std=c++17 -fomit-frame-pointer -Ofast -march=native -ffast-math -mmmx -msse -msse2 -msse3 -DNDEBUG -Wall -fopenmp benchmark.cpp -o benchmark
gcc 8.1.0不會編譯相同的代碼。 我收到該錯誤消息:
/usr/include/c++/8/tr1/cmath:1163:20: error: ‘__gnu_cxx::conf_hypergf’ has not been declared
using __gnu_cxx::conf_hypergf;
我已經檢查了幾個帖子,但是它們很舊或不一樣。
我的問題是:
為什么並行速度較慢?
我使用了錯誤的功能?
在cppreference中,這表示不支持Standardization of Parallelism TS
gcc(表中以紅色表示),並且我的代碼正在並行運行!
您的函數[](auto v){ v=0;}
非常簡單。
可以通過單次調用memset
來替換該函數,也可以將SIMD指令用於單線程並行性。 知道它會覆蓋與向量最初相同的狀態,因此可以優化整個循環。 對於優化器來說,替換std::for_each
比並行實現要容易。
此外,假設並行循環使用線程,則必須記住創建和最終同步(在這種情況下,在處理期間無需同步)會產生開銷,這對於您的瑣碎操作而言可能是很重要的。
線程並行性通常僅在計算量大的任務上值得。 v=0
是存在的計算成本最低的操作之一。
您的基准測試是有缺陷的,我什至感到驚訝,它需要時間來運行。
您寫道:std :: for_each(v.begin(),v.end(),[](auto v){v = 0;});
由於v
是operator()
的局部參數,沒有任何讀取,所以我希望它會被編譯器刪除。 由於您現在有了一個帶有主體的循環,因此可以除去該循環,並且沒有明顯的效果。 與此類似,矢量也可以刪除,因為您沒有任何閱讀器。
因此,沒有任何副作用,可以將其全部消除。 如果您將使用並行算法,那么您可能會有某種同步,這會使優化變得更加困難,因為另一個線程可能會有副作用? 證明它並不更復雜,更不用說可能存在的線程管理的副作用了?
為了解決這個問題,許多基准測試都在宏程序中添加了一些條件,以迫使編譯器承擔副作用。 在lambda中使用它們,以便編譯器不會將其刪除。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.