我需要实现缩减操作(对于每个线程,值应该存储在不同的数组条目中)。但是,对于更多线程,它运行得更慢。有什么建议吗?
double local_sum[16];.
//Initializations....
#pragma omp parallel for shared(h,n,a) private(x, thread_id)
for (i = 1; i < n; i++) {
thread_id = omp_get_thread_num();
x = a + i* h;
local_sum[thread_id] += f(x);
}
最佳答案
您正在经历虚假分享的影响。在 x86 上,单个缓存行的长度为 64 字节,因此包含 64/sizeof(double)
= 8 个数组元素。当一个线程更新其元素时,它运行的核心使用缓存一致性协议(protocol)使所有其他核心中的同一缓存行无效。当另一个线程更新它的元素,而不是直接在缓存上操作时,它的核心必须从上层数据缓存或主内存重新加载缓存行。这会显着降低程序执行速度。
最简单的解决方案是插入填充,从而将不同线程访问的数组元素分散到不同的缓存行中。在 x86 上,这将是 7 个 double
元素。因此,您的代码应如下所示:
double local_sum[8*16];
//Initializations....
#pragma omp parallel for shared(h,n,a) private(x, thread_id)
for (i = 1; i < n; i++) {
thread_id = omp_get_thread_num();
x = a + i* h;
local_sum[8*thread_id] += f(x);
不要忘记在末尾对数组求和时只取第 8 个元素(或将所有数组元素初始化为零)。
关于c - OpenMP 实现还原,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21445901/