我们首先意识到了False Sharing的危险性,尤其是在并行循环中更新数组时。
然而,我发现很难将以下代码片段转换为可并行化的任务,而不会引起False Sharing:
int ii,kk;
double *uk = malloc(sizeof(double) * NX);
double *ukp1 = malloc(sizeof(double) * NX);
double *temp;
double dx = 1.0/(double)NX;
double dt = 0.5*dx*dx;
// Initialise both arrays with values
init(uk, ukp1);
for(kk=0; kk<NSTEPS; kk++) {
for(ii=1; ii<NX-1; ii++) {
ukp1[ii] = uk[ii] + (dt/(dx*dx))*(uk[ii+1]-2*uk[ii]+uk[ii-1]);
}
temp = ukp1;
ukp1 = uk;
uk = temp;
printValues(uk,kk);
}
我的第一反应是尝试分享ukp1:
for(kk=0; kk<NSTEPS; kk++) {
#pragma omp parallel for shared(ukp1)
for(ii=1; ii<NX-1; ii++) {
ukp1[ii] = uk[ii] + (dt/(dx*dx))*(uk[ii+1]-2*uk[ii]+uk[ii-1]);
}
temp = ukp1;
ukp1 = uk;
uk = temp;
printValues(uk,kk);
}
但是这显然与串行版本相比明显减慢了很多。明显的原因是在一些写入操作到ukp1期间发生了False sharing。
我曾经认为也许我可以使用reduction子句,但很快我就发现它不能用于数组。
有什么我可以使用来并行化这段代码以改善运行时间吗?有没有我没听说过的子句可以使用?或者这是需要重新构造代码以允许适当的并行化的任务?
所有形式的输入都将非常感激!
编辑:有人指出我的代码中有一个错误。我本地的代码是正确的,我只是错误地编辑了它(这改变了代码的结构),对此混淆感到抱歉!
编辑2:
@Sergey指出给我一些信息,我觉得很有用:
将 uk 或 ukp1 设置为私有,基本上与将它们设置为共享相同,因为它们都指向同一个内存位置。
理论上使用静态调度应该有所帮助,但我仍然遇到了同样的减速问题。此外,我觉得静态调度不是解决这个问题最可移植的方法。
kk
在循环内部没有被使用,这是有意为之吗? - Sergey L.ukp1
,但从未从中读取,因此每个kk
的迭代都会完全相同。 - Sergey L.