为什么Streams比MergeSort中的ForkJoinPool更快?

时间:2015-04-13 17:50:27

标签: java concurrency java-8 mergesort java-stream

我正在研究我的硕士论文,其中我比较了不同的Java并发机制。从我运行的测试来看,似乎Java 8流在mergesort算法中更快而不是Java 7 ForkJoinPool机制,它是在考虑到分而治之的问题时创建的。

这笔交易是什么?

Stream的引擎盖是什么让它变得更快?

当ForkJoin应该是这类情况下的最佳选择时,如何解释Streams的更好性能。

以下是我的结果(数百万元素/秒的时间):

+-----+---------+--------------+
|     | Streams | ForkJoinPool |
+-----+---------+--------------+
| 1M  | 0.172s  | 0.182s       |
| 2M  | 0.36s   | 0.346s       |
| 3M  | 0.547s  | 0.713s       |
| 4M  | 0.746s  | 0.618s       |
| 5M  | 0.95s   | 1.193s       |
| 6M  | 1.206s  | 1.078s       |
| 7M  | 1.362s  | 1.324s       |
| 8M  | 1.636s  | 1.416s       |
| 9M  | 1.874s  | 1.705s       |
| 10M | 2.133s  | 2.858s       |
+-----+---------+--------------+

这是我正在使用的流:

  public static void sort(int[] numbers) {
     int N = numbers.length;
     int[] temp = new int[N];
     IntStream.range(1, N)
        .filter(n -> (n & -n) == n) // power of 2
        .flatMap(n -> IntStream.iterate(0, i -> i + 2 * n)
        .limit((N - n) / (2 * n) + 1)
        .parallel()
        .map(i -> merge(numbers, temp, i, i + n - 1, Math.min(i + n + n - 1, N - 1))))
    .toArray();
  }

和合并方法:

private static void merge(int[] a, int[] temp, int low, int mid, int high) {
    for (int i = low; i <= high; i++) {
      temp[i] = a[i];
    }
    int i = low, j = mid + 1;
    for (int k = low; k <= high; k++) {
      if (i > mid) {
        a[k] = temp[j++];
      } else if (j > high) {
        a[k] = temp[i++];
      } else if (temp[i] < temp[j]) {
        a[k] = temp[i++];
      } else {
        a[k] = temp[j++];
      }
    }
}

ForkJoinPool主要方法:

@Override
protected void compute() {
  final int range = end - start;
  if (range > blockSize) {
    final int midPoint = start + (range / 2);
    final ForkingAction left = new ForkingAction(start, midPoint, blockSize);
    left.fork();
    final ForkingAction right = new ForkingAction(midPoint + 1, end, blockSize);
    right.compute();
    left.join();
    merge(start, end);
  } else {
    sortSeq(start, end);
  }
}

1 个答案:

答案 0 :(得分:1)

您在FJP版本中使用了join()。 Java7中的Join()在连接线程等待连接完成时创建连续线程。在Java8中,线程只是等待。

Stream使用不使用join()的CountedCompleter类。自2011年以来,我一直在撰写对该框架的持续批评。对于Java8的文章是here如果用CountedCompleter替换RecursiveTask,那么你应该得到更好的结果。使用CountedCompeter类很难。