我运行了一个 JMH 基准测试,其中包含该问题的各种解决方案。我总是在黑洞中消耗 2 个偏移量。结果如下:
Benchmark Mode Cnt Score Error Units
Offset2DBenchmark.doubleLoopWithIf thrpt 3 35425373,827 ± 4242716,439 ops/s
Offset2DBenchmark.loopOverFlatIndex thrpt 3 35929636,197 ± 935681,592 ops/s
Offset2DBenchmark.loopOverIndex thrpt 3 31438051,279 ± 3286314,668 ops/s
Offset2DBenchmark.unrolledLoop thrpt 3 40495297,238 ± 6423961,118 ops/s
Offset2DBenchmark.unrolledLoopWithLambda thrpt 3 27526581,417 ± 1712524,060 ops/s
doubleLoopWithIf = Nested Loops with If to filter 0,0 (TheSorm)
loopOverFlatIndex = Single loop with flattend indizes (Oleg)
loopOverIndex = Single Loop with 2d indizes (Zefick)
unrolledLoop = Completely Unrolled Loop
unrolledLoopWithLambda = Unrolled Loop consuming a Bifunction<Integer, Integer>
因此,展开的循环是最快的。稍慢的是带有 if 语句的双循环和 Oleg 提出的扁平数组。 Zefick 的 2D 数组甚至比您的解决方案还要慢。
作为一个演示,下面是测试的样子:
@Fork(value = 1)
@Warmup(iterations = 3)
@Measurement(iterations = 3)
@Benchmark
public void unrolledLoopWithLambda(Blackhole bh) {
outerOffsets((x, y) -> {
bh.consume(x);
bh.consume(y);
});
}
private void outerOffsets(BiConsumer<Integer, Integer> consumer) {
consumer.accept(-1, -1);
consumer.accept(-1, 0);
consumer.accept(-1, 1);
consumer.accept(0, -1);
consumer.accept(0, 1);
consumer.accept(1, -1);
consumer.accept(1, 0);
consumer.accept(1, 1);
}
因此,除非您想手动展开循环,否则您无法提高性能。
不幸的是,您没有告诉使用循环内的代码是什么样的。如果它甚至有点耗时,那么你如何循环的问题可能会被忽略......
但你的标题表明你希望这个作为二维数组的偏移量。我怀疑您可能会在 x 和 y 的更大循环中使用它。您可以通过使用一维数组并自己计算索引来获得更多性能。
代替:
array[x][y]
使用
array[xy] with xy = x + y * xsize
你应该能够完全避免做乘法。
(这是我第一次使用 JMH 运行基准测试,如果我完全错误地使用它,请告诉我......)