Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/387.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 8流串行与并行性能_Java_Performance_Java 8_Java Stream - Fatal编程技术网

Java 8流串行与并行性能

Java 8流串行与并行性能,java,performance,java-8,java-stream,Java,Performance,Java 8,Java Stream,在我的机器上,以下程序打印: OptionalLong[134043] PARALLEL took 127869 ms OptionalLong[134043] SERIAL took 60594 ms 我不清楚为什么串行执行程序比并行执行快。我在一个相对安静的8gb框中给出了两个程序-Xms2g-Xmx2g。有人能澄清发生了什么事吗 import java.util.stream.LongStream; import java.util.stream.LongStream.Builder

在我的机器上,以下程序打印:

OptionalLong[134043]
 PARALLEL took 127869 ms
OptionalLong[134043]
 SERIAL took 60594 ms
我不清楚为什么串行执行程序比并行执行快。我在一个相对安静的
8gb
框中给出了两个程序
-Xms2g-Xmx2g
。有人能澄清发生了什么事吗

import java.util.stream.LongStream;
import java.util.stream.LongStream.Builder;

public class Problem47 {

    public static void main(String[] args) {

        final long startTime = System.currentTimeMillis();
        System.out.println(LongStream.iterate(1, n -> n + 1).parallel().limit(1000000).filter(n -> fourConsecutives(n)).findFirst());
        final long endTime = System.currentTimeMillis();
        System.out.println(" PARALLEL took " +(endTime - startTime) + " ms");

        final long startTime2 = System.currentTimeMillis();
        System.out.println(LongStream.iterate(1, n -> n + 1).limit(1000000).filter(n -> fourConsecutives(n)).findFirst());
        final long endTime2 = System.currentTimeMillis();
        System.out.println(" SERIAL took " +(endTime2 - startTime2) + " ms");
    }

    static boolean fourConsecutives(final long n) {
        return distinctPrimeFactors(n).count() == 4 &&
                distinctPrimeFactors(n + 1).count() == 4 &&
                distinctPrimeFactors(n + 2).count() == 4 &&
                distinctPrimeFactors(n + 3).count() == 4;
    }

    static LongStream distinctPrimeFactors(long number) {
        final Builder builder = LongStream.builder();
        final long limit = number / 2;
        long n = number;
        for (long i = 2; i <= limit; i++) {
            while (n % i == 0) {
                builder.accept(i);
                n /= i;
            }
        }
        return builder.build().distinct();
    }

}
import java.util.stream.LongStream;
导入java.util.stream.LongStream.Builder;
公共类问题47{
公共静态void main(字符串[]args){
最终长启动时间=System.currentTimeMillis();
System.out.println(LongStream.iterate(1,n->n+1).parallel().limit(1000000).filter(n->fourcontinuives(n)).findFirst());
最终长结束时间=System.currentTimeMillis();
System.out.println(“并行执行”+(endTime-startTime)+“ms”);
最终长startTime2=System.currentTimeMillis();
System.out.println(LongStream.iterate(1,n->n+1).limit(1000000).filter(n->fourcontinuatives(n)).findFirst());
final long-endTime2=System.currentTimeMillis();
System.out.println(“串行数据”+(endTime2-startTime2)+“ms”);
}
静态布尔四连续体(最后一个长n){
返回distinctPrimeFactors(n).count()==4&&
distinctPrimeFactors(n+1).count()==4&&
distinctPrimeFactors(n+2).count()==4&&
distinctPrimeFactors(n+3).count()==4;
}
静态长流distinctTime因子(长数){
最终生成器=LongStream.Builder();
最终长限=数量/2;
长n=数字;

对于(long i=2;i,我们可以使并行执行更容易,但我们不一定使并行更容易

代码中的罪魁祸首是limit+parallel的组合。实现limit()对于顺序流来说很简单,但对于并行流来说却相当昂贵。这是因为limit操作的定义与流的相遇顺序有关。limit()流除非每个元素的计算量非常高,否则并行计算通常比顺序计算慢


您对流源的选择也限制了并行性。使用
iterate(0,n->n+1)
可以得到正整数,但是
iterate
基本上是顺序的;在计算第(n-1)个元素之前,您无法计算第n个元素。因此,当我们尝试拆分此流时,我们最终会拆分(第一个,其余)。请尝试使用
范围(0,k)
来代替;这样可以更好地分割,通过随机访问将其整齐地分成两半。

而Brian Goetz对您的设置是正确的,例如,您应该使用
.range(110000)
而不是
。迭代(1,n->n+1)。限制(1000000)
而且您的基准测试方法非常简单,我想强调一点:

即使在解决了这些问题之后,即使使用挂钟和TaskManager,您也可以看到出了问题。在我的机器上,操作大约需要半分钟,您可以看到并行性在大约两秒钟后下降到单核。即使一个专门的基准工具可以产生不同的结果,这也无关紧要除非您希望始终在基准工具中运行最终应用程序

现在,我们可以尝试对您的设置进行更多的模拟,或者告诉您应该学习有关Fork/Join框架的特殊内容,例如

或者我们尝试另一种实现方式:

ExecutorService es=Executors.newFixedThreadPool(
                       Runtime.getRuntime().availableProcessors());
AtomicLong found=new AtomicLong(Long.MAX_VALUE);
LongStream.range(1, 1000000).filter(n -> found.get()==Long.MAX_VALUE)
    .forEach(n -> es.submit(()->{
        if(found.get()>n && fourConsecutives(n)) for(;;) {
            long x=found.get();
            if(x<n || found.compareAndSet(x, n)) break;
        }
    }));
es.shutdown();
try { es.awaitTermination(Long.MAX_VALUE, TimeUnit.DAYS); }
catch (InterruptedException ex) {throw new AssertionError(ex); }
long result=found.get();
System.out.println(result==Long.MAX_VALUE? "not found": result);
Executors服务=Executors.newFixedThreadPool(
Runtime.getRuntime().availableProcessors());
找到的AtomicLong=新的AtomicLong(Long.MAX_值);
LongStream.range(110000).filter(n->found.get()==Long.MAX\u值)
.forEach(n->es.submit(()->{
如果(;;)的(found.get()>n&&fourcontinuives(n)){
长x=found.get();

if(xThanks for your response Brian.那么,如果我要取消限制,我应该看到性能特征有利于并行解决方案吗?在取消限制()后,我得到:OptionalLong[134043]并行时间59341毫秒OptionalLong[134043]串行时间57290毫秒我刚刚注意到您的流源使用iterate(),这也是基本上连续的(在计算#(n-1)之前无法计算元素#n),因此分割效果很差。请尝试用范围(0,100000)替换iterate()。哦,您还应该使用一个像样的微基准线束,如JMH。您的代码显示了所有经典的微基准标记错误(预热不足,可能会出现非优化偏差等。否则,这些数字就没有真正意义。我还建议确保
distinctPrimeFactors()
中的
LongStream
是顺序的。您不想在已经并行化的任务中尝试并行化。不要使用
System.currentTimeMillis()
用于测量经过的时间。使用
System.currentTimeMillis()的结果
将受到系统时钟变化的影响,例如由用户或NTP更新等触发。感谢您的回答。如果您在Brian的回答中看到我的评论,您会发现原则上我同意他的意见,但指出框架中很可能存在错误。我不知道您链接的线程-因此因此,您的方法可能很好地解决了这个问题,但一般来说(当任务不能很容易地被分割成大小相等的任务时),您会发现ExecutorService中的共享工作队列很快就会成为争用瓶颈。您描述的方法只适用于最粗粒度的并行。@Brian Goetz:只要所有任务都是CPU密集型的,它们的大小不必相等,所有CPU核都会有一些工作要做。我的解决方案的主要问题是当任务非常小时(甚至更糟,当热点优化器可以省略在简单循环中执行的操作时),开销是增加的