我有两个版本的代码对角遍历MxN矩阵.显然,即使使用相同的(糟糕的)遍历逻辑,使用Java Streams的版本运行速度比不使用Java Streams的版本慢5倍.

约束条件:

  • 1<=M,N<=10^4
  • 1 = M * N = 10 ^4<<

Version 1: Using for loops:

public int[] findDiagonalOrder(int[][] mat) {
        int M = mat.length;
        int N = mat[0].length;

        int[] traversal = new int[M * N];
        int s = 0;
        for(int sum=0; sum < M+N; sum++) {
            for(int k=0; k<=sum; k++) {
                int row = (sum%2 == 0) ? sum - k : k;
                if (row < M && (sum-row < N))
                    traversal[s++] = mat[row][sum-row];
            }
        }
        return traversal;
}

Version 2: Using Java Streams:

    public int[] findDiagonalOrder(int[][] matrix) {
        int M = matrix.length;
        int N = matrix[0].length;

        return IntStream.range(0, M+N)
                .flatMap(sum -> IntStream.rangeClosed(0, sum)
                        .filter(i -> {
                            int row = (sum%2 == 0) ? (sum-i) : i;
                            return row < M && (sum - row) < N;
                        })
                        .map(i -> (sum%2 == 0) ? matrix[sum-i][i] : matrix[i][sum-i]))
                .toArray();
    }

版本#1的运行时间约为353 msec,而版本#2的运行时间约为1500 msec.我想知道,是什么导致了性能下降?我甚至没有使用Boxing/Unboxing,这可能会产生影响.

PS:我知道有一个更好的方法来进行矩阵遍历O(M * N),但我的问题是关于Streams.

推荐答案

我想知道,是什么导致了性能下降?

简单的答案是probably个流间接费用.

性能不是Java流的主要目标. 在当前版本的Java中,编译器还不能将基于流的代码转换为性能与classic 循环一样好的本地代码. 在future ,这种情况可能会改变. 然而,要实现这一目标,需要付出大量的研发努力,而且(AFAIK)目前这并不是Java团队的优先事项.&

因此,简单的"推论"是,如果性能1是给定代码片段2的最重要需求,那么您不应该在解决方案中使用流.

我甚至没有使用Boxing/Unboxing,这可能会产生影响.

没有明确表示. 但这could是在被子下发生的. 唯一绝对确定的方法是分析JIT编译器3发出的所有本机代码. 分析你的基准可能也会给你答案...如果答案是幕后有拳击/拆箱.><

最后,由于您还没有向我们展示完整的基准测试,因此很可能您的结果(353 msec与1500 msec)并不代表相应代码在生产环境中的执行情况. 阅读How do I write a correct micro-benchmark in Java?和答案引用的各种来源.


1.当前的实际表现,而不是future 的潜在表现.
2、但通常情况并非如此. 即使在性能关键型应用程序中,该应用程序的大多数代码行对整体性能也没有显著影响.
3—字节码不能给出代码性能的可靠指示. 优化由JIT编译器而不是字节码编译器完成. 可能有指令在字节码中进行装箱和拆箱,这些字节码在本地代码中被完全优化.

Java相关问答推荐

如果给定层次 struct 级别,如何从其预序穿越构造n元树

Java中不同包中的类之间的配置共享

CSS应用于一个端点,但不应用于Thymeleaf中的另一个端点

在for—each循环中的AnimationTimer中的if语句'

相同的Java SerializedLambda为implMethodKind返回不同的结果

什么是Java原子属性的正确getter和setter

Com.google.firebase.database.DatabaseException:无法将类型为java.lang.Boolean的值转换为字符串.这是关于什么的?

将响应转换为带值的键

对于亚洲/香港,使用ResolverStyle.STRICT的LocalDate.parse返回意外结果

我可以在MacOS上使用什么Java函数来在适当的设备上以适当的音量播放适当的alert 声音?

如何将其他属性引用到log4j2 yaml配置中?

使用While循环打印素数,无法正常工作

Java组件项目中的JavaFX对话框国际化

IntelliJ IDEA依赖项工具窗口丢失

找出承载Cargo 的最小成本

项目react 堆中doOnComplete()和Subscribe()的第三个参数之间的差异

有没有办法在o(log(N))中以系统的方式将数组中的小块元素复制和移动到新增长的数组中的左侧?

如何从命令行编译包中的所有类?

为什么创建Java动态代理需要接口参数

模拟JUnit未检测到返回字符串的方法的任何声纳覆盖