Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/338.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何在java中安全地使用并行流?_Java_Parallel Processing - Fatal编程技术网

如何在java中安全地使用并行流?

如何在java中安全地使用并行流?,java,parallel-processing,Java,Parallel Processing,我在一个大型计算中使用了并行流,但是当我执行它时,结果很奇怪。当在纯[SEQ]进程调度中执行所有操作时,它工作得很好 为了找到问题,我使用了一个简单的计算,工作是将从“迭代次数”到零的所有自然数相加: private long sum = 0; // global helper public static void main(String args[]) { int iterations = 50000; // the targe

我在一个大型计算中使用了并行流,但是当我执行它时,结果很奇怪。当在纯[SEQ]进程调度中执行所有操作时,它工作得很好

为了找到问题,我使用了一个简单的计算,工作是将从“迭代次数”到零的所有自然数相加:

private long sum = 0;                  // global helper

public static void main(String args[])
{
    int iterations = 50000;            // the target number

    // solving the task parallel
    // ---------------------------------- <Section-under-Test>.START
    final long    startPAR =     System.nanoTime();
    IntStream.range(1, iterations+1).parallel().forEach(i->{

        sum += i;
    });
    final long durationPAR = ( ( System.nanoTime() - startPAR ) / 1_000_000 );
    // ---------------------------------- <Section-under-Test>.FINISH
    long sumParallel = sum; sum = 0;   // save + reset variable

    System.out.println( "Sum parallel: "  + sumParallel
                      + "         TOOK: " + durationPAR
                        );

    // solving the task linear using one core
    // ---------------------------------- <Section-under-Test>.START
    final long    startSEQ =     System.nanoTime();

    for(int i = 1; i < iterations+1; i++)
    {
        sum += i;
    }
    final long durationSEQ = ( ( System.nanoTime() - startSEQ ) / 1_000_000 );
    // ---------------------------------- <Section-under-Test>.FINISH

    System.out.println( "Sum serial:   "  + sum
                      + "         TOOK: " + durationSEQ
                        );
    System.out.println((sum == sumParallel));
}
所以我想知道的是: 为什么会这样? 如何预防呢? 我是否没有抓住要点,想在错误的地方使用并行计算

信息: 在我更大的计算中,我计算的是这个值,在这个例子中,这个值加在和上。这样就可以了。但是我如何正确地将这个结果添加到全局变量中呢?

因为sum+=I;不是原子的,它涉及多个操作:

读我 读和 计算和加i 将结果分配给sum 在执行这些操作的任何时候,我们都有其他线程执行相同的操作。如果两个线程同时读取求和运算2,则肯定会得到不同的结果,因为当它们都计算求和+i时,两个线程都没有考虑另一个线程的加法

如果您想并行进行这样的计算,请使用。像addAndGet这样的操作保证是原子的,也就是说,它保证在一个步骤中发生,而不是分解成上面的步骤。

因为sum+=i;不是原子的,它涉及多个操作:

读我 读和 计算和加i 将结果分配给sum 在执行这些操作的任何时候,我们都有其他线程执行相同的操作。如果两个线程同时读取求和运算2,则肯定会得到不同的结果,因为当它们都计算求和+i时,两个线程都没有考虑另一个线程的加法

如果您想并行进行这样的计算,请使用。addAndGet之类的操作保证是原子的,也就是说,它保证在一个步骤中发生,并且不会分解为上述步骤。

只需使用.sum方法,这样就不会有线程在共享状态下运行,因此不需要同步或原子访问:

int sum = IntStream.rangeClosed(1, iterations).parallel().sum();
如果需要对计算进行更多控制,可以使用.reduce方法:

只要使用.sum方法,就不会有线程在共享状态下运行,因此不需要同步或原子访问:

int sum = IntStream.rangeClosed(1, iterations).parallel().sum();
如果需要对计算进行更多控制,可以使用.reduce方法:


非常整洁,谢谢。另一个小问题:是否有类似原子双精度的东西?对于您的用例来说,似乎是一个很好的解决方案。非常整洁,谢谢。另一个小问题:是否有类似AtomicDouble的东西?对于您的用例,这似乎是一个很好的解决方案。您是否介意为每个测试运行使用System.nanoTime添加测量的持续时间?不仅要测量结果的正确性,而且要测量使用[SEQ]v/s[PAR]的成本,因为[SEQ]v/s[PAR]是由并行流方法和过程调度策略实现的。其中一个方面的差异已经让您感到惊讶,但在专业软件工程设计实践中,不阅读第二个方面更是一种罪过。您是否愿意使用计时+发布结果[SEQ]和[PAR]持续时间来重新运行测试?谢谢。@user3666197当然,这是我第二件要做的事。事实上,与PAR相比,Seq的运行速度明显快了12秒到7秒,当然速度更快。原因很多。好吧,我的许多帖子都得到了很多歇斯底里的否决票,这纯粹是一种愤怒的惩罚,一次解释,为什么在InMOS硬件并行Transputers时代之后,[PAR]的附加成本实际上很多次都不是真的-[parallel],而是一个公正的-[CONCURRENT]进程调度更重要,比任何简单的输入和使用这样的语法构造函数。。。有兴趣吗?>>您是否介意在已经添加了测量值的地方重新运行上述更新的代码,而不是.sum或.reduce方法,因为即使是错误的[PAR]结果实际上也可能比纯[SEQ]方法花费更多的成本-处理并发布更新后的精确数字以及您执行的CPU内核数量,甚至可能尝试添加一些预热+多次测量循环,以过滤一些系统执行噪音,但硬事实很重要,以便看到整个画面清晰、可靠,对吗?您是否介意使用System.nanoTime为每个测试运行添加测量的持续时间?不仅要测量结果的正确性,而且要测量使用[SEQ]v/s[PAR]的成本,因为[SEQ]v/s[PAR]是由并行流方法和过程调度策略实现的。其中一个方面的差异已经让您感到惊讶,但在专业软件工程设计实践中,不阅读第二个方面更是一种罪过。您是否愿意使用计时+发布结果[SEQ]和[PAR]持续时间来重新运行测试?谢谢。@user3666197当然,这是我第二件要做的事。事实上,它是图尔
与PAR相比,NED的速度明显快于12秒,而不是7秒。当然,速度更快。原因很多。好吧,我的许多帖子都得到了很多歇斯底里的否决票,这纯粹是一种愤怒的惩罚,一次解释,为什么在InMOS硬件并行Transputers时代之后,[PAR]的附加成本实际上很多次都不是真的-[parallel],而是一个公正的-[CONCURRENT]进程调度更重要,比任何简单的输入和使用这样的语法构造函数。。。有兴趣吗?>>您是否介意在已经添加了测量值的地方重新运行上述更新的代码,而不是.sum或.reduce方法,因为即使是错误的[PAR]结果实际上也可能比纯[SEQ]方法花费更多的成本-处理并发布更新后的精确数字以及您执行的CPU内核数量,甚至可能尝试添加一些预热+多次测量循环,以过滤一些系统执行噪音,但硬事实很重要,以便看到整个画面清晰和声音,对吗?
int sum = IntStream.rangeClosed(1, iterations).parallel().reduce(0, (a, b) -> a + b);