什么时候应该优先使用流而不是传统循环以获得最佳性能?流是否利用分支预测?
什么时候应该优先使用流而不是传统循环以获得最佳性能?流是否利用分支预测?
我刚刚阅读了有关分支预测的内容,并想尝试使用Java 8的Streams来测试它的工作原理。
然而,与传统的循环相比,使用Streams的性能总是更差。
int totalSize = 32768; int filterValue = 1280; int[] array = new int[totalSize]; Random rnd = new Random(0); int loopCount = 10000; for (int i = 0; i < totalSize; i++) { // array[i] = rnd.nextInt() % 2560; // 无序数据 array[i] = i; // 排序数据 } long start = System.nanoTime(); long sum = 0; for (int j = 0; j < loopCount; j++) { for (int c = 0; c < totalSize; ++c) { sum += array[c] >= filterValue ? array[c] : 0; } } long total = System.nanoTime() - start; System.out.printf("条件运算符时间:%d ns,(%f 秒)%n", total, total / Math.pow(10, 9)); start = System.nanoTime(); sum = 0; for (int j = 0; j < loopCount; j++) { for (int c = 0; c < totalSize; ++c) { if (array[c] >= filterValue) { sum += array[c]; } } } total = System.nanoTime() - start; System.out.printf("分支语句时间:%d ns,(%f 秒)%n", total, total / Math.pow(10, 9)); start = System.nanoTime(); sum = 0; for (int j = 0; j < loopCount; j++) { sum += Arrays.stream(array).filter(value -> value >= filterValue).sum(); } total = System.nanoTime() - start; System.out.printf("Streams时间:%d ns,(%f 秒)%n", total, total / Math.pow(10, 9)); start = System.nanoTime(); sum = 0; for (int j = 0; j < loopCount; j++) { sum += Arrays.stream(array).parallel().filter(value -> value >= filterValue).sum(); } total = System.nanoTime() - start; System.out.printf("并行Streams时间:%d ns,(%f 秒)%n", total, total / Math.pow(10, 9));
输出:
1. 对于排序数组:
条件运算符时间:294062652 ns,(0.294063 秒) 分支语句时间:272992442 ns,(0.272992 秒) Streams时间:806579913 ns,(0.806580 秒) 并行Streams时间:2316150852 ns,(2.316151 秒)
2. 对于无序数组:
条件运算符时间:367304250 ns,(0.367304 秒) 分支语句时间:906073542 ns,(0.906074 秒) Streams时间:1268648265 ns,(1.268648 秒) 并行Streams时间:2420482313 ns,(2.420482 秒)
我尝试使用`List`来运行相同的代码:
将`Arrays.stream(array)`替换为`list.stream()`,
将`array[c]`替换为`list.get(c)`。
输出:
1. 对于排序列表:
条件运算符时间:860514446 ns,(0.860514 秒) 分支语句时间:663458668 ns,(0.663459 秒) Streams时间:2085657481 ns,(2.085657 秒) 并行Streams时间:5026680680 ns,(5.026681 秒)
2. 对于无序列表:
条件运算符时间:704120976 ns,(0.704121 秒) 分支语句时间:1327838248 ns,(1.327838 秒) Streams时间:1857880764 ns,(1.857881 秒) 并行Streams时间:2504468688 ns,(2.504469 秒)
我参考了一些博客这个和这个,这些博客也指出了Streams的性能问题。
1. 我同意使用Streams编程在某些场景下更加方便,但是当我们在性能上失去优势时,为什么还要使用它们?我是否遗漏了什么?
2. 在哪种情况下Streams的性能与循环相当?是否仅在您定义的函数执行时间很长,而循环性能可以忽略不计的情况下?
3. 在任何情况下,我都没有看到Streams利用了分支预测(我尝试了排序和无序的Streams,但没有用)。与普通的Streams相比,它的性能影响超过了两倍。