确认 JMH 循环和流性能基准测试的有效性

Confirm validity of JMH benchmarks of for loop and streams performance

我决定对简单的流操作进行一些测量,将它们与相应的预流迭代结构进行比较。

我有一个一定长度的ArrayList,这样所有的列表元素都是三字符的字符串。

以下是相关的基准测试方法:

@Benchmark
public long shortLengthConstantSizeFor() {
    long count   = 0;
    for (String val : shortLengthListConstantSize) {
        if (val.length() == 3) { ++ count; }
    }
    return count;
}

@Benchmark
public long shortLengthConstantSizeForEach() {
    IntHolder   intHolder   = new IntHolder();
    shortLengthListConstantSize.forEach(s -> { if (s.length() == 3) ++ intHolder.value; } );
    return intHolder.value;
}

@Benchmark
public long shortLengthConstantSizeLambda() {
    return shortLengthListConstantSize.stream().filter(s -> s.length() == 3).count();
}

@Benchmark
public long shortLengthConstantSizeLambdaParallel() {
    return shortLengthListConstantSize.stream().parallel().filter(s -> s.length() == 3).count();
}

我想向社区确认的是,这些是否 "functionally equivalent",并且是否真的在衡量他们看似在衡量的东西。我在这里不提供测量值,因为那样会分散注意力。

注意 "shortLength" 指的是 "short list"。我也有这些方法的几个块,具有不同长度的列表,最多一个包含 300k 个元素。

如果 "functional equivalence" 你的意思是每种方法执行相同的功能或测量,包括副作用 - 看起来是这样。

有人可能会争辩说,在第二种方法中,您应该使用 LongHolder 而不是 IntHolder 来匹配函数的密码域。但是,如果您的 "value" 实际上是 class 中的 long - 那么它就是通过了。

值得一提的是,count() 只是 map(x -> 1L).sum() 的 shorthand,但对于此基准测试没有任何改变。