性能概况

使用并行STL的首要原因,肯定是性能。

下面的代码就能反映不同执行策略的性能差异。

  1. // parallelSTLPerformance.cpp
  2. #include <algorithm>
  3. #include <cmath>
  4. #include <chrono>
  5. #include <execution>
  6. #include <iostream>
  7. #include <random>
  8. #include <string>
  9. #include <vector>
  10. constexpr long long size = 500'000'000;
  11. const double pi = std::acos(-1);
  12. template <typename Func>
  13. void getExecutionTime(const std::string& title, Func func) {
  14. const auto sta = std::chrono::steady_clock::now();
  15. func();
  16. const std::chrono::duration<double> dur = std::chrono::steady_clock::now() - sta;
  17. std::cout << title << ": " << dur.count() << " sec." << std::endl;
  18. }
  19. int main() {
  20. std::cout << std::endl;
  21. std::vector<double> randValues;
  22. randValues.reserve(size);
  23. std::mt19937 engine;
  24. std::uniform_real_distribution<> uniformDist(0, pi / 2);
  25. for (long long i = 0; i < size; ++i) randValues.push_back(uniformDist(engine));
  26. std::vector<double> workVec(randValues);
  27. getExecutionTime("std::execution::seq", [workVec]()mutable {
  28. std::transform(std::execution::seq, workVec.begin(), workVec.end(),
  29. workVec.begin(),
  30. [](double arg) {return std::tan(arg); }
  31. );
  32. });
  33. getExecutionTime("std::execution::par", [workVec]()mutable {
  34. std::transform(std::execution::par, workVec.begin(), workVec.end(),
  35. workVec.begin(),
  36. [](double arg) {return std::tan(arg); }
  37. );
  38. });
  39. getExecutionTime("std::execution::par_unseq", [workVec]()mutable {
  40. std::transform(std::execution::par_unseq, workVec.begin(), workVec.end(),
  41. workVec.begin(),
  42. [](double arg) {return std::tan(arg); }
  43. );
  44. });
  45. }

parallelSTLPerformance.cpp统计了串行(第39行)、并行(第46行)和向量化并行(第53行)执行策略的耗时。首先,randValues由区间在[0,pi/2)的5亿个数字填充。函数模板getExecutionTime(第16 - 24行)获取标题和Lambda函数,在第20行执行Lambda函数,并显示执行耗时(第22行)。程序使用了三个Lambda函数(第39、46和53行),它们被声明为mutable。因为Lambda函数修改它的参数workVec,而Lambda函数默认是不能对其进行修改的。如果Lambda函数想要修改,那么就必须声明为mutable

我的windows笔记本电脑有8个逻辑核心,但并行执行速度要比串行的快10倍以上。

性能概况 - 图1

并行执行和并行向量化执行的性能大致相同。Visual C++团队的博客对此进行了解释:使用C++17并行算法更好的性能。Visual C++团队使用相同的方式实现了并行计算和并行策略,所以目前就不要期望par_unseq有更好性能(但未来就不好说了)。