Сравнительный анализ параллельной сортировки слиянием — найден порог определения

Я пытаюсь определить, что является разумным порогом, для которого следует прекратить подразделять мою реализацию 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, но это должно влиять только на первые несколько итераций, нет? Ищу совет по алгоритму или почему мой результат так далек от того, что я ожидаю.


person Tiago Redaelli    schedule 30.04.2019    source источник
comment
Оформить заказ JMH. Несколько примеров здесь.   -  person priyank-sriv    schedule 30.04.2019


Ответы (1)


Оптимальный порог — это тот, который позволяет параллельно выполнять столько потоков, сколько ядер в вашей системе.

Если ваша система имеет cores ядер, пороговое значение должно быть проверено и инициализировано с помощью

SortTask.threshold = cores > 0 ? (a.length + cores - 1) / cores : a.length;

Улучшение скорости будет меньше, чем количество ядер, потому что последние несколько фаз слияния не могут выполняться параллельно.

Поскольку вы сортируете массив из 108 элементов, оптимальный порог действительно где-то между 107 и 108, если только у вас не более 10 ядер.

person chqrlie    schedule 01.05.2019
comment
Это относится только к сортировке слиянием, поскольку она разбивает подмассивы на две части одинакового размера. Если вы используете Quicksort, часть будет более изменчивой, и порог будет другим, не так ли? - person Tiago Redaelli; 07.05.2019