gpt4 book ai didi

Java8 Parallel Stream 花时间求和值

转载 作者:搜寻专家 更新时间:2023-11-01 01:49:07 25 4
gpt4 key购买 nike

我正在练习 java8 并行流部分并编写一个程序,将作为参数传递的数字从 0 加到该数字。

例如,如果我传递了 10,它将对从 1 到 10 的数字求和并返回输出。

程序如下

public class ParellelStreamExample {



public static void main(String[] args) {
System.out.println("Long Range value - "+ Long.MIN_VALUE + " to "+ Long.MAX_VALUE);
long startTime = System.nanoTime();
long sum = sequentailSum(100000000);
System.out.println(
"Time in sequential execution " + (System.nanoTime() - startTime) / 1000000 + " msec with sum = " + sum);
long startTime1 = System.nanoTime();
long sum1 = parellelSum(100000000);
System.out.println("Time in parallel execution " + (System.nanoTime() - startTime1) / 1000000
+ " msec with sum = " + sum1);

}

private static Long parellelSum(long n) {
return Stream.iterate(1l, i -> i + 1).limit(n).parallel().reduce(0L, Long::sum);
}

private static Long sequentailSum(long n) {
return Stream.iterate(1l, i -> i + 1).limit(n).reduce(0L, Long::sum);
}
}

我收到的输出是

Long Range value - -9223372036854775808 to 9223372036854775807
Time in sequential execution 1741 msec with sum = 5000000050000000

Exception in thread "main" java.lang.OutOfMemoryError
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
at java.util.concurrent.ForkJoinTask.getThrowableException(ForkJoinTask.java:598)
at java.util.concurrent.ForkJoinTask.reportException(ForkJoinTask.java:677)
at java.util.concurrent.ForkJoinTask.invoke(ForkJoinTask.java:735)
at java.util.stream.SliceOps$1.opEvaluateParallelLazy(SliceOps.java:155)
at java.util.stream.AbstractPipeline.sourceSpliterator(AbstractPipeline.java:431)
at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:233)
at java.util.stream.ReferencePipeline.reduce(ReferencePipeline.java:474)
at com.abhishek.javainaction.stream.parellel.ParellelStreamExample.parellelSum(ParellelStreamExample.java:21)
at com.abhishek.javainaction.stream.parellel.ParellelStreamExample.main(ParellelStreamExample.java:14)
Caused by: java.lang.OutOfMemoryError: GC overhead limit exceeded
at java.lang.Long.valueOf(Long.java:840)
at com.abhishek.javainaction.stream.parellel.ParellelStreamExample.lambda$0(ParellelStreamExample.java:21)
at com.abhishek.javainaction.stream.parellel.ParellelStreamExample$$Lambda$3/250421012.apply(Unknown Source)
at java.util.stream.Stream$1.next(Stream.java:1033)
at java.util.Spliterators$IteratorSpliterator.trySplit(Spliterators.java:1784)
at java.util.stream.AbstractShortCircuitTask.compute(AbstractShortCircuitTask.java:114)
at java.util.concurrent.CountedCompleter.exec(CountedCompleter.java:731)
at java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:289)
at java.util.concurrent.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1056)
at java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1692)
at java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:157)

为什么这个程序没有并行运行并且发生了gc开销,相反,它应该在并行部分运行得更快,因为它使用 fork/join 框架并通过内部线程进行处理。

哪里出了问题?

最佳答案

这里有几处出错了。

  1. 您正在尝试使用 System.nanoTime() 而不是 JMH 之类的东西来对代码进行基准测试。
  2. 您正在尝试对 Long 进行简单计算 (sum),而不是使用 LongStream。如果 JVM 无法摆脱装箱,指针追踪的开销很容易压倒并行性的好处。
  3. 您正在尝试对由 iterate 生成的固有顺序流进行并行化处理。流框架将尝试通过缓冲流并将其分派(dispatch)给多个线程来完成您的要求,这会增加很多开销。
  4. 您正在对有序并行流使用 limit。这需要流框架进行大量额外的同步,以确保正好使用 n 个第一个元素来生成结果。您会看到,如果将 .unordered() 放入并行流中,执行时间将显着减少,但结果将是不确定的,因为您将得到 some n 个元素,而不是 firstn 个元素。

正确的做法是使用 JMH 并将 iterate(...).limit(...) 替换为 LongStream.rangeClosed(1, n)

关于Java8 Parallel Stream 花时间求和值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51183438/

25 4 0