Openmp嵌套for循环与有序输出

时间:2017-05-05 11:21:33

标签: c++ for-loop output openmp

我目前正试图找到一种快速可靠的方法来并行化一组循环,如果我需要在内循环中保存结果的条件。 该代码应该通过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;
        }
    }
}

1 个答案:

答案 0 :(得分:0)

首先,您需要解决并行版本中的错误。您在竞争条件下写入共享变量phipoint(并行外循环)和phiplaneRpointzpoint(任何并行循环)。您必须声明那些私有,或者更好的是,首先在本地声明它们(这使它们隐式私有)。这样代码就更容易推理 - 这对于并行代码非常重要。

如您所描述的那样并行化外循环是显而易见且非常有效的方法。如果存在严重的负载不平衡(stc->r <= 0.174未在点之间均匀分布),您可能希望使用schedule(dynamic)

在您的情况下,并行化内部循环似乎是不必要的。通常外部循环提供更高的效率,因为更少的开销 - 除非它们没有暴露足够的并行工作,有一些竞争条件,有依赖性或缓存问题。然而,尝试衡量它是一项值得的练习。但是,如果不止一个phis满足条件,则在写入densityarr时可能存在竞争条件。总的来说,循环似乎有点奇怪 - 因为你只使用densityarr中的最多一个结果,你可能宁愿反转循环并在找到第一个循环后取消。这有助于串行执行很多,但可能会抑制并行化。此外,如果您没有找到满足条件的phi - 或者如果该点不在容器中,则densityarr中的相应条目仍然未初始化 - 这可能非常危险,因为您以后无法确定是否价值是否有效。

一般说法,除非您需要,否则不要使用new分配对象。只需将pos放在堆栈上,就可以为您提供更好的性能。在(并行)循环中分配内存可能是一个性能问题,因此您可能需要重新考虑获取Toroidal的方式。

请注意,我确实假设TubePlanes[phiInd].getMinDistDensity没有副作用,否则并行化会有问题。