java - 为什么在合并排序中 Streams 比 ForkJoinPool 更快?

标签 java concurrency java-8 mergesort java-stream

我正在写我的硕士论文,其中比较了不同的 Java 并发机制。从我运行的测试来看,Java 8 流在合并排序算法中似乎比 Java 7 ForkJoinPool 机制更快,后者是在考虑分而治之问题的情况下创建的。

这是怎么回事?

Streams 的底层是什么让它运行得更快?

当 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);
  }
}

最佳答案

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

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

关于java - 为什么在合并排序中 Streams 比 ForkJoinPool 更快?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29611784/

相关文章:

visual-studio-2010 - Visual Studio 2008对新.NET 4的支持

objective-c - 核心数据: concurency conflict between save and fetch

java - 如何过滤动态嵌套的列表对象java 8

Java 列表流 anyMatch 返回错误结果

Java 8 Streams : why does Collectors. toMap 对于带有通配符的泛型表现不同?

java - 使用 ImageIO 将 CGM 转换为 PNG 图像

java - Jsoup 停止解析网页

java - Float 和 BigDecimal 精度差异

java - 关闭语音识别对话框时为空对象

java - 更新 jlabel