1

由于 c++17,std 库具有并行算法,所以我尝试使用以下代码,对数字列表求和,并想看看是否有任何性能提升。

#include <algorithm>
#include <chrono>
#include <execution>
#include <numeric>
#include <iostream>
#include <vector>

int main() {
  size_t n = 100000000;
  std::vector<size_t> vec(n);
  std::iota(vec.begin(), vec.end(), 0);

  auto par_sum = [&](size_t k) {
    auto t1 = std::chrono::high_resolution_clock::now();

    std::vector<size_t> rez(k);
    std::iota(rez.begin(), rez.end(), 0);
    size_t batch = static_cast<size_t>(n / k) + 1;
    std::for_each(std::execution::par_unseq, rez.begin(), rez.end(),
      [&](size_t id) {
        size_t cum = 0;
        for (size_t i = id*batch; i < std::min((id+1)*batch, n); ++i) {
          cum += vec[i];
        }
        rez[id] = cum;
    });

    auto t2 = std::chrono::high_resolution_clock::now();
    auto duration = std::chrono::duration_cast<std::chrono::microseconds>( t2 - t1 ).count();
    std::cout << "n_worker = " << k
      << ", time = " << duration
      << ", rez = " << std::accumulate(rez.begin(), rez.end(), 0lu)
      << std::endl;
  };

  par_sum(1);
  par_sum(3);
  par_sum(5);
}

编译

g++  -std=c++17 -L/usr/local/lib -O3 -mavx -ltbb a.cpp

结果表明

n_worker = 1, time = 51875, rez = 4999999950000000
n_worker = 3, time = 57616, rez = 4999999950000000
n_worker = 5, time = 63193, rez = 4999999950000000

问题,

  • 对 1 个工人没有性能提升,为什么?
4

1 回答 1

2

我会假设,对于少量的工作,可能会通过纯粹保持在 L1 缓存上下文中而在一个 CPU 中执行紧密循环。一旦你增加了相同数据的并行量,你就会开始调用缓存一致性和页面错误的开销。

可能值得您查看计算缓存未命中的方法,例如此处建议的方法:以 编程方式计算缓存错误

另请参阅: 什么是“缓存友好”代码?

加上“缓存友好代码”和“面向数据的设计”的其他资源: https ://www.youtube.com/watch?v=b5v9aElYU2I

https://youtu.be/fHNmRkzxHWs

这与此处解释 的虚假共享有关: https ://www.youtube.com/watch?v=dznxqe1Uk3E

于 2020-10-12T19:58:21.793 回答