Java 在写入外部变量时,使用流并行化内部循环

Java 在写入外部变量时,使用流并行化内部循环,java,parallel-processing,java-stream,Java,Parallel Processing,Java Stream,我一直坚持并行化以下代码: 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

我一直坚持并行化以下代码:

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]
    }
}

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

第一个循环的结果是:

  • 变量
    d的增量
  • f的值
  • 新的
    c[i]
    子数组
要计算它们,您可以创建一个自定义类型来保存这3个值,然后执行可变缩减来计算所有3个值。由于没有更好的名称,我将调用自定义类型
ResultContainer

类似地,第二个循环的结果是数组
a[i]
。这很简单,因为从
流构建数组很容易

因此,这将提供:

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();
}
for(int i0=1;i0新结果容器(y),(结果容器,j)->{
双a1=a[i-1][j];
双a2=a[i][j];
双a3=a1*a2;
双cij=c[i-1][j]+a3;
结果容器。添加(-a3,cij*a3,j,cij);
},结果容器::添加);
d+=结果d;
e[i]=d+结果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];
        }
    }
}
类结果容器{
双d;
双f;
双[]ci;
公共结果容器(int y){
这是d=0;
这个。f=0;
ci=新的双精度[y];
}
公共无效添加(双d、双f、整数j、双cij){
这个.d+=d;
这个.f+=f;
ci[j]=cij;
}
公共作废添加(结果容器结果容器2){
d+=结果容器2.d;
f+=结果容器2.f;
对于(int j=0;j
简短回答:不要使用并行。我可以说,间接费用远远超过了实际收益。你试过什么?你拥有1.4k的声誉,但似乎仍然不知道该问什么。目前,您已经向我们展示了以旧方式工作(很好)的代码。但你的尝试在哪里?你在哪里挣扎?请澄清并编辑您的问题。因为现在只是。“请为我做这些工作”而且我在你的代码中没有看到任何流。你想简单地用流重写你的代码吗?因为我相信你至少可以在你的电脑上尝试一下own@Samuel您能为
a,b,c,d
提供样本输入和样本输出吗?@user1516873外循环迭代取决于以前的迭代(读取
a[i-1]
和写入
a[i]
,所以它不能并行。谢谢@Didier L!正在收敛到类似的东西,但你在我之前就已经让它工作了。干得好!
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];
        }
    }
}