【发布时间】:2018-05-04 05:12:23
【问题描述】:
我只是在评估,哪个代码 sn-ps 在 java 8 中的性能更好。
片段 1(在主线程中处理):
public long doSequence() {
DoubleStream ds = IntStream.range(0, 100000).asDoubleStream();
long startTime = System.currentTimeMillis();
final AtomicLong al = new AtomicLong();
ds.forEach((num) -> {
long n1 = new Double (Math.pow(num, 3)).longValue();
long n2 = new Double (Math.pow(num, 2)).longValue();
al.addAndGet(n1 + n2);
});
System.out.println("Sequence");
System.out.println(al.get());
long endTime = System.currentTimeMillis();
return (endTime - startTime);
}
片段 2(并行线程处理):
public long doParallel() {
long startTime = System.currentTimeMillis();
final AtomicLong al = new AtomicLong();
DoubleStream ds = IntStream.range(0, 100000).asDoubleStream();
ds.parallel().forEach((num) -> {
long n1 = new Double (Math.pow(num, 3)).longValue();
long n2 = new Double (Math.pow(num, 2)).longValue();
al.addAndGet(n1 + n2);
});
System.out.println("Parallel");
System.out.println(al.get());
long endTime = System.currentTimeMillis();
return (endTime - startTime);
}
代码片段 3(在线程池中的并行线程中处理):
public long doThreadPoolParallel() throws InterruptedException, ExecutionException {
ForkJoinPool customThreadPool = new ForkJoinPool(4);
DoubleStream ds = IntStream.range(0, 100000).asDoubleStream();
long startTime = System.currentTimeMillis();
final AtomicLong al = new AtomicLong();
customThreadPool.submit(() -> ds.parallel().forEach((num) -> {
long n1 = new Double (Math.pow(num, 3)).longValue();
long n2 = new Double (Math.pow(num, 2)).longValue();
al.addAndGet(n1 + n2);
})).get();
System.out.println("Thread Pool");
System.out.println(al.get());
long endTime = System.currentTimeMillis();
return (endTime - startTime);
}
输出在这里:
Parallel
6553089257123798384
34 <--34 milli seconds
Thread Pool
6553089257123798384
23 <--23 milli seconds
Sequence
6553089257123798384
12 <--12 milli seconds!
我的预期是
1) 使用线程池进行处理的时间应该是最短的,但事实并非如此。(注意我没有包括线程池的创建时间,所以应该很快)
2) 没想到顺序运行的代码是最快的,应该是什么原因。
我使用的是四核处理器。
感谢任何帮助解释上述歧义!
【问题讨论】:
-
您是否阅读过 Java 中正确的微基准测试? stackoverflow.com/questions/504103/… -- 你实际上是如何调用你的基准测试的?你在预热 JVM 吗?
-
@ErwinBolwidt 我没有遵循微基准测试中提到的所有要点。但在打印上述数字之前,我已经完成了 JVM 预热。顺序处理总是比其他同行快,这真是令人费解!
-
您的线程可能在原子操作上花费了太多时间。
-
首先,您应该使用
System.nanoTime()来测量经过的时间。此外,如果您声称要测试流处理,则应该进行流处理而不是伪装的循环代码,即IntStream.range(0, 100000) .parallel() .map(num -> (long)Math.pow(num, 3) + (long)Math.pow(num, 2)) .sum()。然后,尝试使用更大的范围来查看它是如何扩展的。这允许识别固定开销部分。请注意,顺便说一下,当不通过new Double(…).longValue()对其进行混淆时,对long的转换如何变得更简单...... -
map→mapToLong...
标签: java multithreading java-8 java-stream