代码之家  ›  专栏  ›  技术社区  ›  Samuel

写入外部变量时将内部循环与流并行化

  •  0
  • Samuel  · 技术社区  · 8 年前

    我一直在把下面的代码并行化:

    double[][] a, b, c;
    double d;
    double[] e;
    for (int i = 1; i < x; i++) {
        double f = 0.0;
        for (int j = 0; j < y; j++) {
            double a1 = a[i-1][j];
            double a2 = a[i][j];
            double a3 = a1 * a2;
            d -= a3;
            c[i][j] = c[i - 1][j] + a3;
            f += c[i][j] * a3;
        }
        e[i] = d + f;
        for (int j = 0; j < y; j++) {
            a[i][j] = e[i] * b[i][j]
        }
    }
    

    第二个内环依赖于第一个(因为 e[i] )因此,它们必须按顺序执行,但在它们中的每一个中,计算可以并行化 y 是的。

    问题是它们同时读取和写入外部变量。编写可以并行化(概念上),因为每个内部循环将其部分结果聚合到全局变量。

    x 大约是10000 是的 250英镑。在本例中,内环处理被简化,但实际上计算量更大。

    这里的问题是如何并行化读写外部变量的循环?

    以下尝试无法编译,因为 d f 以下内容:

    double[][] a, b, c;
    double d;
    double[] e;
    for (int i = 1; i < x; i++) {
        double f = 0.0;
        IntStream.range(0, y).parallel().forEach(j -> {  
            double a1 = a[i-1][j];
            double a2 = a[i][j];
            double a3 = a1 * a2;
            d -= a3;
            c[i][j] = c[i - 1][j] + a3;
            f += c[i][j] * a3;
        });
        e[i] = d + f;
        IntStream.range(0, y).parallel().forEach(j -> {  
            a[i][j] = e[i] * b[i][j];
        });
    }
    
    1 回复  |  直到 8 年前
        1
  •  1
  •   Didier L    8 年前

    要并行化子循环,必须首先了解每个子循环的结果。

    第一个循环的结果是:

    • 变量的增量 d
    • 价值 f
    • 新的 c[i] 子阵列

    要计算它们,可以创建一个自定义类型来保存3个值,然后执行可变缩减来计算所有3个值。由于没有更好的名称,我将调用自定义类型 ResultContainer 是的。

    类似地,第二个循环的结果是数组 a[i] .这更简单,因为从 Stream 是的。

    因此,这将给予:

    for (int i0 = 1; i0 < x; i0++) {
        final int i = i0; // tmp store as final for use in lambda
        ResultContainer result = IntStream.range(0, y).parallel()
                .collect(() -> new ResultContainer(y), (resultContainer, j) -> {
                    double a1 = a[i - 1][j];
                    double a2 = a[i][j];
                    double a3 = a1 * a2;
                    double cij = c[i - 1][j] + a3;
                    resultContainer.add(-a3, cij * a3, j, cij);
                }, ResultContainer::add);
    
        d += result.d;
        e[i] = d + result.f;
        c[i] = result.ci;
        a[i] = IntStream.range(0, y).parallel().mapToDouble(j -> e[i] * b[i][j]).toArray();
    }
    

    根据我们的定制类型:

    class ResultContainer {
        double d;
        double f;
        double[] ci;
    
        public ResultContainer(int y) {
            this.d = 0;
            this.f = 0;
            ci = new double[y];
        }
    
        public void add(double d, double f, int j, double cij) {
            this.d += d;
            this.f += f;
            ci[j] = cij;
        }
    
        public void add(ResultContainer resultContainer2) {
            d += resultContainer2.d;
            f += resultContainer2.f;
            for (int j = 0; j < ci.length; j++) {
                // note that one of the two is always 0 here
                ci[j] += resultContainer2.ci[j];
            }
        }
    }
    
    推荐文章