Java并行流性能

时间:2014-04-10 21:16:23

标签: java performance parallel-processing microbenchmark

在玩新的Java流时,我注意到与并行流的性能有关的奇怪之处。我使用了一个简单的程序,它从文本文件中读取单词并计算长度大于>的单词。 5(测试文件有30000字):

    String contents = new String(Files.readAllBytes(Paths.get("text.txt")));
    List<String> words = Arrays.asList(contents.split("[\\P{L}]+"));
    long startTime;
    for (int i = 0; i < 100; i++) {
        startTime = System.nanoTime();
        words.parallelStream().filter(w -> w.length() > 5).count();
        System.out.println("Time elapsed [PAR]: " + (System.nanoTime() - startTime));
        startTime = System.nanoTime();
        words.stream().filter(w -> w.length() > 5).count();
        System.out.println("Time elapsed [SEQ]: " + (System.nanoTime() - startTime));
        System.out.println("------------------");
    }

这会在我的机器上生成以下输出(我只提到第一次和最后一次循环迭代):

Time elapsed [PAR]: 114185196
Time elapsed [SEQ]: 3222664
------------------
Time elapsed [PAR]: 569611
Time elapsed [SEQ]: 797113
------------------
Time elapsed [PAR]: 678231
Time elapsed [SEQ]: 414807
------------------
Time elapsed [PAR]: 755633
Time elapsed [SEQ]: 679085
------------------
Time elapsed [PAR]: 755633
Time elapsed [SEQ]: 393425
------------------
...
Time elapsed [PAR]: 90232
Time elapsed [SEQ]: 163785
------------------
Time elapsed [PAR]: 80396
Time elapsed [SEQ]: 154805
------------------
Time elapsed [PAR]: 83817
Time elapsed [SEQ]: 154377
------------------
Time elapsed [PAR]: 81679
Time elapsed [SEQ]: 186449
------------------
Time elapsed [PAR]: 68849
Time elapsed [SEQ]: 154804
------------------

为什么第一次处理比其他处理慢100倍?为什么并行流比第一次迭代中的顺序流慢,但它在上一次迭代中的速度是原来的两倍?为什么顺序和并行流都会随着时间的推移变得更快?这与循环优化有关吗?

稍后编辑:在Luigi的建议下,我使用JUnitBenchmarks实施了基准测试:

List<String> words = null;

@Before
public void setup() {
    try {
        String contents = new String(Files.readAllBytes(Paths.get("text.txt")));
        words = Arrays.asList(contents.split("[\\P{L}]+"));
    } catch (IOException e) {
        e.printStackTrace();
    }
}

@BenchmarkOptions(benchmarkRounds = 100)
@Test
public void parallelTest() {
    words.parallelStream().filter(w -> w.length() > 5).count();
}

@BenchmarkOptions(benchmarkRounds = 100)
@Test
public void sequentialTest() {
    words.stream().filter(w -> w.length() > 5).count();
}

我还将测试文件中的单词数增加到300000.新结果是:

  

Benchmark.sequentialTest:[测量105轮中的100轮,线程:1   (顺序)]

     

round:0.08 [+ - 0.04],round.block:0.00 [+ - 0.00],round.gc:0.00 [+ -   0.00],GC.calls:62,GC.time:1.53,time.total:8.65,time.warmup:0.81,time.bench:7.85

     

Benchmark.parallelTest:[测量105轮中的100轮,线程:1   (顺序)]

     

round:0.06 [+ - 0.02],round.block:0.00 [+ - 0.00],round.gc:0.00 [+ -   0.00],GC.calls:32,GC.time:0.79,time.total:6.82,time.warmup:0.39,time.bench:6.43

所以看起来初始结果是由错误的微基准配置引起的......

1 个答案:

答案 0 :(得分:2)

Hotspot JVM以解释模式开始执行程序,并在经过一些分析后将常用部分编译为本机代码。由于这个原因,循环的初始迭代通常很慢。