并行合并排序基准测试 - 确定找到的阈值
Parallel Mergesort benchmarking - determining threshold found
我正在尝试确定停止细分我的 Mergesort 实现的合理阈值。
然而,我得到的结果是阈值应该介于 107 < x < 108 之间,这是荒谬的鉴于 java 使用的默认阈值约为 8192。这基本上告诉我细分几乎总是不好的,阈值越高越好,因为它执行的拆分更少。
它目前做的工作是对一个大小为108,随机范围为0
到1000
的浮点数组进行排序.相同的随机数组被重复用于每个测试的阈值。
public class ParallelMergeSort extends SortStrategy {
@Override
public long sort(float[] a, int cores, int threshold) {
System.gc();
long start = System.nanoTime();
RecursiveAction mainTask = new SortTask(a, 0, a.length - 1);
SortTask.threshold = threshold;
ForkJoinPool pool = new ForkJoinPool(cores);
pool.invoke(mainTask);
return System.nanoTime() - start;
}
private static class SortTask extends RecursiveAction {
private float[] a;
private int left, right;
private static int threshold;
SortTask(float[] a, int left, int right) {
this.a = a;
this.left = left;
this.right = right;
}
@Override
protected void compute() {
if (left < right) {
if ((right - left) < threshold) {
Arrays.sort(a, left, right + 1);
} else {
int mid = (left + right)/2;
invokeAll(
new SortTask(a, left, mid),
new SortTask(a, mid + 1, right)
);
// Merge
int n1 = mid - left + 1;
int n2 = right - mid;
float a1[] = new float[n1];
float a2[] = new float[n2];
// Fill sub arrays
for (int i = 0; i < n1; ++i)
a1[i] = a[left + i];
for (int j = 0; j < n2; ++j)
a2[j] = a[mid + 1 + j];
// Sort and merge
int l = 0, r = 0, o = left;
while (l < a1.length && r < a2.length) {
if (a1[l] <= a2[r])
a[o++] = a1[l++];
else
a[o++] = a2[r++];
}
// Merge remaining
while (l < a1.length)
a[o++] = a1[l++];
while (r < a2.length)
a[o++] = a2[r++];
}
}
}
}
}
我知道 JVM 由于 JIT 可能不可靠,但它应该只影响前几次迭代,不是吗?寻求有关算法的建议或为什么我的结果与我的预期相差甚远。
最佳阈值是允许运行 与系统中的内核一样多的线程并行。
如果您的系统有 cores
个核心,阈值应该是 test 应该用
初始化
SortTask.threshold = cores > 0 ? (a.length + cores - 1) / cores : a.length;
由于最后几个合并阶段无法运行并行,因此速度提升将小于内核数量。
由于您正在对 108 个元素的数组进行排序,最佳阈值确实介于 107 和 108,除非你有超过10个核心。
我正在尝试确定停止细分我的 Mergesort 实现的合理阈值。
然而,我得到的结果是阈值应该介于 107 < x < 108 之间,这是荒谬的鉴于 java 使用的默认阈值约为 8192。这基本上告诉我细分几乎总是不好的,阈值越高越好,因为它执行的拆分更少。
它目前做的工作是对一个大小为108,随机范围为0
到1000
的浮点数组进行排序.相同的随机数组被重复用于每个测试的阈值。
public class ParallelMergeSort extends SortStrategy {
@Override
public long sort(float[] a, int cores, int threshold) {
System.gc();
long start = System.nanoTime();
RecursiveAction mainTask = new SortTask(a, 0, a.length - 1);
SortTask.threshold = threshold;
ForkJoinPool pool = new ForkJoinPool(cores);
pool.invoke(mainTask);
return System.nanoTime() - start;
}
private static class SortTask extends RecursiveAction {
private float[] a;
private int left, right;
private static int threshold;
SortTask(float[] a, int left, int right) {
this.a = a;
this.left = left;
this.right = right;
}
@Override
protected void compute() {
if (left < right) {
if ((right - left) < threshold) {
Arrays.sort(a, left, right + 1);
} else {
int mid = (left + right)/2;
invokeAll(
new SortTask(a, left, mid),
new SortTask(a, mid + 1, right)
);
// Merge
int n1 = mid - left + 1;
int n2 = right - mid;
float a1[] = new float[n1];
float a2[] = new float[n2];
// Fill sub arrays
for (int i = 0; i < n1; ++i)
a1[i] = a[left + i];
for (int j = 0; j < n2; ++j)
a2[j] = a[mid + 1 + j];
// Sort and merge
int l = 0, r = 0, o = left;
while (l < a1.length && r < a2.length) {
if (a1[l] <= a2[r])
a[o++] = a1[l++];
else
a[o++] = a2[r++];
}
// Merge remaining
while (l < a1.length)
a[o++] = a1[l++];
while (r < a2.length)
a[o++] = a2[r++];
}
}
}
}
}
我知道 JVM 由于 JIT 可能不可靠,但它应该只影响前几次迭代,不是吗?寻求有关算法的建议或为什么我的结果与我的预期相差甚远。
最佳阈值是允许运行 与系统中的内核一样多的线程并行。
如果您的系统有 cores
个核心,阈值应该是 test 应该用
SortTask.threshold = cores > 0 ? (a.length + cores - 1) / cores : a.length;
由于最后几个合并阶段无法运行并行,因此速度提升将小于内核数量。
由于您正在对 108 个元素的数组进行排序,最佳阈值确实介于 107 和 108,除非你有超过10个核心。