什么流是如此之快

时间:2016-08-11 14:28:12

标签: java performance java-stream

我试图从Coursera实施一个程序。程序声明是:

给定一系列非负整数a0,...,an-1,找到最大的成对乘积,即可以通过将两个不同的元素与序列相乘得到的最大整数。

我正在尝试各种方法来实施解决方案并检查哪种方法效果最佳。

我看到流仍然很快。

为什么会这样?

我受到了印象,然后找到最大的2个元素而没有排序和乘以它们将是最好的。流排序(顺序流比并行流更快)比这种方法提供更好的结果吗?

我的计划

    import java.util.ArrayList;
    import java.util.Comparator;
    import java.util.List;
    import java.util.Random;
    import java.util.stream.Collectors;

    public class MaxProduct {
        public static void main(String[] args) {
            List<Long> testList = createRandomArrayOfSize(30000000);

            warmup(testList);
            System.out.println("Warmup done");

            Measure.meaureTime("No sorting, finding largest 2 elements and multiplying",
                    () -> findMaxProductByFindingLargest2Elements(new ArrayList<>(testList)));
            Measure.meaureTime("Sorting, Multiplying last 2 elements",
                    () -> findMaxProductUsingSorting(new ArrayList<>(testList)));
            Measure.meaureTime("Sorting using streams, Multiplying last 2 elements",
                    () -> findMaxProductUsingStreamSorting(new ArrayList<>(testList)));
            Measure.meaureTime("Parallel sorting using streams, Multiplying last 2 elements by reduction",
                    () -> findMaxProductReducingParallelStream(new ArrayList<>(testList)));
        }

        public static long findMaxProductByFindingLargest2Elements(List<Long> list) {
            long largest = 0;
            long secondlargest = 0;
            for (Long no : list) {
                if (no > largest) {
                    secondlargest = largest;
                    largest = no;
                }
            }
            return largest * secondlargest;
        }

        public static long findMaxProductUsingSorting(List<Long> list) {
            list.sort(Comparator.naturalOrder());
            return list.get(list.size() - 1) * list.get(list.size() - 2);
        }

        public static long findMaxProductUsingStreamSorting(List<Long> list) {
            List<Long> collect = list.stream().sorted(Comparator.naturalOrder()).collect(Collectors.toList());
            return collect.get(list.size() - 1) * collect.get(list.size() - 2);
        }

        public static long findMaxProductReducingParallelStream(List<Long> list) {
            return list.parallelStream().sorted(Comparator.reverseOrder()).limit(2).reduce((x, y) -> x * y).get();
        }

        private static class Measure {
            private static final int NO_OF_ITERATIONS = 3;

            private static void meaureTime(String description, Runnable runnable) {
                long startTime = System.nanoTime();
                for (int i = 0; i < NO_OF_ITERATIONS; i++) {
                    runnable.run();
                }
                long timeTakenInNanos = System.nanoTime() - startTime;
                System.out.println(description + " : " + (timeTakenInNanos / 3));
            }
        }

        private static void warmup(List<Long> testList) {
            findMaxProductByFindingLargest2Elements(new ArrayList<>(testList));
            findMaxProductUsingSorting(new ArrayList<>(testList));
            findMaxProductUsingStreamSorting(new ArrayList<>(testList));
            findMaxProductReducingParallelStream(new ArrayList<>(testList));
        }

        private static List<Long> createRandomArrayOfSize(int size) {
            return new Random().longs(size, 1, 10000000).boxed().collect(Collectors.toList());
        }
    }

更新结果

没有排序,找到最大的2个元素并乘以:778547847
排序,乘以最后2个元素:13423659115
使用流进行排序,乘以最后2个元素:15518997158
使用流进行并行排序,通过缩减将最后2个元素相乘:5405983848

更新了代码

第一种方法存在错误。如果最大的no在第零个索引处,则产品将为零。需要解决这个问题。

流不快
我的测试代码出错了。修正了错误。现在按预期工作。

2 个答案:

答案 0 :(得分:2)

不幸的是,流不一定很快。

findMaxProductUsingStreamSorting指定了一个Stream,但没有通过collectfindFirst实现它。它不会改变列表。因此,只有两个列表的产品才会被完成。结果也是错误的。

使用Stream,迭代的执行时间较晚,因此排序,过滤等可能会使执行变得聪明。

答案 1 :(得分:0)

您的测试存在缺陷。运行流测试的时间已经对列表进行了排序,这就是它快速的原因。