我正在研究我的硕士论文,其中我比较了不同的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);
}
}
答案 0 :(得分:1)
您在FJP版本中使用了join()。 Java7中的Join()在连接线程等待连接完成时创建连续线程。在Java8中,线程只是等待。
Stream使用不使用join()的CountedCompleter类。自2011年以来,我一直在撰写对该框架的持续批评。对于Java8的文章是here如果用CountedCompleter替换RecursiveTask,那么你应该得到更好的结果。使用CountedCompeter类很难。