简体   繁体   English

使用 Streams 实现最佳性能的嵌套循环

[英]Nested loops with using Streams to achieve best performance

I started learning Java 8 features, streams and lambdas in particular, and I'm quite confused.我开始学习 Java 8 个特性,尤其是流和 lambda,我很困惑。 I tried to rewrite the piece of code below我试图重写下面的代码

MyClass graph = new MyClass(V);

for (int i = 0; i < numOfVertices; i++) {
   for (int j = 0; j < numOfVertices; j++) {
      if (adjMatrix[i][j] != 0) {
         graph.addEdge(i, j, adjMatrix[i][j]);
      }
   }
}

I wrote this:我写了这个:

int b = IntStream.range(0, numOfVertices - 1).parallel()
   .map(i -> (IntStream.range(0, numOfVertices - 1))
      .map(j -> {
         if (adjMatrix[i][j] != 0) {
            graph.addEdge(i, j, adjMatrix[i][j]);
         }
      }));

Of course it doesn't work.当然是行不通的。 What would be the proper way to rewrite the code above?重写上面的代码的正确方法是什么? I'm also looking for the best performance, so I attempted to use the parallel method.我也在寻找最好的性能,所以我尝试使用并行方法。

Thanks!谢谢!

Regardless to performance this is a simple form rewriting it with stream:无论性能如何,这都是用 stream 重写它的简单形式:

                IntStream.range(0, numOfVertices - 1)
                 .forEach(i -> IntStream.range(0, numOfVertices - 1)
                   .filter(j -> adjMatrix[i][j] != 0)
                     .forEach(j -> graph.addEdge(i, j, adjMatrix[i][j])));

Short answer简短的回答

If you want "best performance", the shorter time in iteration: Use "for loop" for small matrix, for bigger cases you can consider use "parallel streams"如果您想要“最佳性能”,迭代时间更短:对于小矩阵使用“for循环”,对于更大的情况,您可以考虑使用“并行流”

.. long answer ..长答案

I created a test to measure the average time of execution one of three options.我创建了一个测试来测量三个选项之一的平均执行时间。

"For loop:" “for循环:”

for (int i = 0; i < size; i++) {
    for (int j = 0; j < size; j++) {
        doSomething(numOfVertices[i][j]);
    }
}

"IntStream.range:" “IntStream.range:”

IntStream.range(0, size)
        .forEach(i -> (IntStream.range(0, size))
                .forEach(j -> {
                    doSomething(numOfVertices[i][j]);
                }));

"IntStream.range parallel:" “IntStream.range 并行:”

IntStream.range(0, size).parallel()
        .forEach(i -> (IntStream.range(0, size))
                .forEach(j -> {
                    doSomething(numOfVertices[i][j]);
                }));

This section was removed as I could not simpulate it's time cost:此部分已删除,因为我无法模拟它的时间成本:

      if (adjMatrix[i][j] != 0) {
         graph.addEdge(i, j, adjMatrix[i][j]);
      }

Below is the whole test code that perform measurement for different matrix.下面是对不同矩阵执行测量的整个测试代码。 It runs every case 10000 times and gives the average time.它运行每个案例 10000 次并给出平均时间。 Here are the results for run on my computer.这是在我的计算机上运行的结果。 For small matrix (form 1 x 1 to 100 x 100) for loop is the best option.对于小矩阵(从 1 x 1 到 100 x 100),for 循环是最佳选择。 When matrix is big (more than 500 x 500) using "IntStream.range parallel" is faster.当矩阵很大(超过 500 x 500)时,使用“IntStream.range parallel”会更快。 "IntStream.range" is always worse than "For loop" for every case.对于每种情况,“IntStream.range”总是比“For loop”差。

Size: 1
IntStream.range parallel: 0.002300
         IntStream.range: 0.002200
                For loop: 0.000000
Size: 5
IntStream.range parallel: 0.023000
         IntStream.range: 0.000500
                For loop: 0.000000
Size: 10
IntStream.range parallel: 0.025800
         IntStream.range: 0.000300
                For loop: 0.000100
Size: 50
IntStream.range parallel: 0.042200
         IntStream.range: 0.004300
                For loop: 0.000900
Size: 100
IntStream.range parallel: 0.035000
         IntStream.range: 0.006000
                For loop: 0.004300
Size: 500
IntStream.range parallel: 0.060200
         IntStream.range: 0.102000
                For loop: 0.079600
Size: 1000
IntStream.range parallel: 0.122000
         IntStream.range: 0.379800
                For loop: 0.347400
    public static void main(String[] args) {

        Arrays.asList(1, 5, 10, 50, 100, 500, 1000).forEach(
                size -> {
                    System.out.println("Size: " + size);
                    Integer[][] numOfVertices = createArray(size);

                    Map<String, Runnable> toRun = Map.of(
                            "For loop:",
                            () -> {
                                for (int i = 0; i < size; i++) {
                                    for (int j = 0; j < size; j++) {
                                        doSomething(numOfVertices[i][j]);
                                    }
                                }
                            },
                            "IntStream.range:",
                            () -> {
                                IntStream.range(0, size)
                                        .forEach(i -> (IntStream.range(0, size))
                                                .forEach(j -> {
                                                    doSomething(numOfVertices[i][j]);
                                                }));
                            },
                            "IntStream.range parallel:",
                            () -> {
                                IntStream.range(0, size).parallel()
                                        .forEach(i -> (IntStream.range(0, size))
                                                .forEach(j -> {
                                                    doSomething(numOfVertices[i][j]);
                                                }));
                            }
                    );

                    int howManyTimes = 10000;
                    Map<String, Double> map = new HashMap<>();
                    toRun.entrySet().forEach(e -> {
                        double time = (((double)IntStream.range(0, howManyTimes).mapToObj(
                                (x) -> executionTime(e.getValue()))
                                .reduce(Long::sum).get()) / howManyTimes);

                        map.put(e.getKey(), time);
                    });

                    map.entrySet().forEach(e -> {
                        System.out.println(String.format("%25s %f", e.getKey(), e.getValue()));
                    });
                }
        );
    }

    private static Integer[][] createArray(int size) {
        Integer[][] val = new Integer[size][size];
        IntStream.range(0, size).forEach(
                i -> IntStream.range(0,size).forEach(
                        j -> val[i][j] = (int)(Math.random() * 100)
                )
        );
        return  val;
    }

    private static int doSomething(int val) {
        return val * val;
    }

    private static long executionTime(Runnable execThis)
    {
        long startTime = System.currentTimeMillis();
        execThis.run();
        long endTime = System.currentTimeMillis();
        return (endTime-startTime);
    }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM