我目前正试图找到一种快速可靠的方法来并行化一组循环,如果我需要在内循环中保存结果的条件。 该代码应该通过3D网格中的大量点。对于此卷中的某些点,我必须检查另一个条件(检查角度),如果满足此条件,我必须计算密度。
到目前为止,最快的方法是#pragma omp parallel for private (x,y,z) collapse(3)
在所有for循环之外,#pragma omp parallel for
用于最内层循环(phiInd),它不仅是最大的循环,而且还调用CPU密集型函数。 / p>
我需要将密度值存储在内环中的densityarr中。然后密度阵列单独保存。 我现在的问题是,根据我设置的线程数,我得到不同的结果,y密度数组。串行版本和只有1个线程的openmp运行具有相同的结果。 增加线程数会导致相同点的结果,但这些结果与串行版本不同。
我知道有#pragma omp for ordered
,但这导致计算速度太慢。
有没有办法并行化这个循环,同时仍然根据我的点(x,y,z)得到我的结果?
或者更清楚:为什么增加线程数会改变我的结果?
double phipoint, Rpoint, zpoint;
double phiplane;
double distphi = 2.0 * M_PI / nPlanes; //set desired distace to phi to assign point to fluxtubeplane
double* densityarr = new double[max_x_steps * max_y_steps * max_z_steps];
for (z = 0; z < max_z_steps; z++) {
for (x = 0; x < max_x_steps; x++) {
for (y = 0; y < max_y_steps; y++) {
double x_center = x * stepSizeGrid - max_x / 2;
double y_center = y * stepSizeGrid - max_y / 2;
double z_center = z * stepSizeGrid - max_z / 2;
cartesianCoordinate* pos = new cartesianCoordinate(x_center, y_center, z_center);
linearToroidalCoordinate* tor = linearToroidal(*pos);
simpleToroidalCoordinate* stc = simpleToroidal(*pos);
phipoint = tor->phi;
if (stc->r <= 0.174/*0.175*/) {//check if point is in vessel
for (int phiInd = 0; phiInd < nPlanes; ++phiInd) {
phiplane = phis[phiInd];
if (abs(phipoint - phiplane) <= distphi) {//find right plane for point
Rpoint = tor->R;
zpoint = tor->z;
densityarr[z * max_y_steps * max_x_steps + x * max_y_steps + y] = TubePlanes[phiInd].getMinDistDensity(Rpoint, zpoint);
}
}
}
delete pos, tor, stc;
}
}
}
答案 0 :(得分:0)
首先,您需要解决并行版本中的错误。您在竞争条件下写入共享变量phipoint
(并行外循环)和phiplane
,Rpoint
,zpoint
(任何并行循环)。您必须声明那些私有,或者更好的是,首先在本地声明它们(这使它们隐式私有)。这样代码就更容易推理 - 这对于并行代码非常重要。
如您所描述的那样并行化外循环是显而易见且非常有效的方法。如果存在严重的负载不平衡(stc->r <= 0.174
未在点之间均匀分布),您可能希望使用schedule(dynamic)
。
在您的情况下,并行化内部循环似乎是不必要的。通常外部循环提供更高的效率,因为更少的开销 - 除非它们没有暴露足够的并行工作,有一些竞争条件,有依赖性或缓存问题。然而,尝试衡量它是一项值得的练习。但是,如果不止一个phis满足条件,则在写入densityarr
时可能存在竞争条件。总的来说,循环似乎有点奇怪 - 因为你只使用densityarr
中的最多一个结果,你可能宁愿反转循环并在找到第一个循环后取消。这有助于串行执行很多,但可能会抑制并行化。此外,如果您没有找到满足条件的phi - 或者如果该点不在容器中,则densityarr
中的相应条目仍然未初始化 - 这可能非常危险,因为您以后无法确定是否价值是否有效。
一般说法,除非您需要,否则不要使用new
分配对象。只需将pos
放在堆栈上,就可以为您提供更好的性能。在(并行)循环中分配内存可能是一个性能问题,因此您可能需要重新考虑获取Toroidal
的方式。
请注意,我确实假设TubePlanes[phiInd].getMinDistDensity
没有副作用,否则并行化会有问题。