【发布时间】:2018-06-18 15:49:57
【问题描述】:
这是一段用于多线程向量求和的 C++11 代码。
#include <thread>
template<typename ITER>
void sum_partial(ITER a, ITER b, double & result) {
result = std::accumulate(a, b, 0.0);
}
template<typename ITER>
double sum(ITER begin, ITER end, unsigned int nb_threads) {
size_t len = std::distance(begin, end);
size_t size = len/nb_threads;
std::vector<std::thread> thr(nb_threads-1);
std::vector<double> r(nb_threads);
size_t be = 0;
for(size_t i = 0; i < nb_threads-1; i++) {
size_t en = be + size;
thr[i] = std::thread(sum_partial<ITER>, begin + be, begin + en, std::ref(r[i]));
be = en;
}
sum_partial(begin + be, begin + len, r[nb_threads-1]);
for(size_t i = 0; i < nb_threads-1; i++)
thr[i].join();
return std::accumulate(r.begin(), r.end(), 0.0);
}
典型的用法是 sum(x.begin(), x.end(), n) 和 x 一个双精度向量。
这是一个图表,显示计算时间作为线程数的函数(求和 10⁷ 值的平均时间,在没有其他任何运行的 8 核计算机上 - 我在 32 核计算机上尝试过,行为非常类似)。
为什么可扩展性这么差?可以改进吗?
我的(非常有限的)理解是,为了具有良好的可扩展性,线程应该避免在同一个缓存行中写入。这里所有线程都写入r 一次,在它们计算的最后,我不希望它成为限制因素。是内存带宽问题吗?
【问题讨论】:
-
需要 y 轴上的单位。
-
@UKMonkey 只需几秒钟,但我认为这并不重要......
-
好吧,如果需要 Milliseconds to create thread: 0.015625 看起来线程创建可能是您的瓶颈 - 如果您的单位错误
-
@Elvis 这就是单位很重要的原因。
-
@Elvis 是的,你错了。
std::accumulate被定义为左折叠,矢量化会破坏这一点,因为浮点加法 is not associative。 (根据 fp 严格性设置,库/编译器可能会这样做。)我肯定会反对使用std::accumulate以获得最佳性能。
标签: c++ multithreading scalability