我有以下代码(只是我为这个问题编写的一个例子),它只是计算一个范围的总和 我用三种方式实现了它:
令人惊讶的是,Serial方法是最快的方法。实际上,其他两个时间需要%10 。
Java Stream的正确配置是什么,以使其更快? 我做错了什么?
package ned.main;
import java.util.Date;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ForkJoinPool;
import java.util.stream.IntStream;
public class TestParallelStream {
static private void testParallelStream() {
System.setProperty("java.util.concurrent.ForkJoinPool.common.parallelism", "1000000");
ForkJoinPool forkJoinPool = new ForkJoinPool(10000);
Date start = new Date();
long sum1 = 0;
for (int i = 0; i < 1_000_000; ++i) {
sum1 += i * 10;
}
Date start1 = new Date();
long sum2 = IntStream.range(1, 1_000_000)
.parallel()
.map(x -> x * 10)
.sum();
Date start2 = new Date();
try {
long sum3 = forkJoinPool.submit(() ->
IntStream
.range(1, 1_000_000)
.parallel()
.map(x -> x * 10)
.sum())
.get();
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
long serial = start1.getTime() - start.getTime();
long parallelstream = start2.getTime() - start1.getTime();
long withfork = start2.getTime() - start1.getTime();
System.out.println(serial + "," + parallelstream + "," + withfork);
}
public static void main(String[] args) {
testParallelStream();
}
}
由于
答案 0 :(得分:2)
似乎对并行属性有一个根本错误的理解。要将所有CPU内核用于计算,并行性应与内核数相匹配,这已经是默认值。
将并行度设置为1000000是没有意义的 - 即使在不太可能的情况下你真的有1000000个处理器,因为在这种情况下,设置已经是默认值的设置仍然是过时的。作为旁注,如果您有1000000个处理单元,那么由1000000次乘法组成的作业将太小而无法从此硬件中受益。你为每个int
乘法开始一个线程,这是疯了。
如果有疑问,请不要乱用该设置并将并行性保留为默认值。
它还取决于实际操作,是否会受益于并行处理。 JVM的优化器将仅处理小块的顺序代码,因此将操作拆分为块以便并行处理可能会降低代码优化的好处。
在最极端的变体中,形式为
的循环long sum1 = 0;
for(int i=from; i<to; ++i) sum1 += i * constant;
可以优化到
long sum1=((long)from+to-1)*(to-from)/2 * constant;
这会导致任意范围的计算时间不变,因此将范围拆分为子范围(并行计算)通常无法缩短所需的时间。但那当然是特定于JVM的。
对于具有一些非常严格的内联阈值的HotSpot,可能会发生使用流代码执行操作超过它们,从而降低JVM的优化潜力。是否发生这种情况,可以通过对等效的顺序流操作进行基准测试来进行测试。在最好的情况下,它应该像循环一样执行。如果没有,您知道流操作将对将应用于并行流的循环具有缺点。调整JVM选项可能会有所帮助(希望将来默认会变得更加“流友好”)。
答案 1 :(得分:0)
根据我的个人经验,串行流是99%任务的最佳选择,比较并行流。 以下是Doug Lea的When to use parallel streams文章。基本上,考虑在当且仅当您遇到性能问题时使用并行流。有一些提示:
就我个人而言,我认为并行流过于强调日常编码。