自 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 个工作人员,性能没有提升,为什么?
最佳答案
我认为,对于少量工作,可能会出现这样的情况:通过纯粹保留在 L1 缓存上下文中,可以在一个 CPU 中执行紧密循环。一旦您增加相同数据的并行度,您就会开始调用缓存一致性和页面错误方面的开销。
您可能值得研究一下计算缓存未命中的方法,例如此处建议的方法: Programmatically counting cache faults
另请参阅: What is a "cache-friendly" code?
以及有关“缓存友好代码”和“面向数据的设计”的其他资源: https://www.youtube.com/watch?v=b5v9aElYU2I
和 https://youtu.be/fHNmRkzxHWs
这与虚假共享有关,解释如下: https://www.youtube.com/watch?v=dznxqe1Uk3E
关于C++ std 库并行执行 for_each 比顺序循环慢,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64324386/