Я пытаюсь создать параллельную реализацию для сортировки выбора, но в конечном итоге это происходит медленнее, чем последовательный - PullRequest
0 голосов
/ 14 мая 2019

Для моего класса параллельных вычислений мне нужно подумать и создать параллельную реализацию алгоритма сортировки выбора.Идея состоит в том, чтобы иметь возможность масштабировать его на несколько потоков, чтобы он стал быстрее, чем последовательная реализация.

Моя идея заключалась в следующем: Идея сортировки с параллельным выбором

За последние несколько дней я создал следующую реализацию, но она намного медленнее, чем последовательный алгоритм.Всякий раз, когда я использую больше потоков, это также намного медленнее, чем когда я использую один поток.Я впервые работаю с потоками, поэтому не уверен, правильно ли я это реализовал.

SelectionSort.java

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

public class SelectionSort {
    private static final int availableProcessors = Runtime.getRuntime().availableProcessors();
    private static final int NUMBER_COUNT = 10000;
    private static List<Integer> sortedList = new ArrayList<>();
    private static int[][] splitArray;
    private static List<Integer> lowestNumbers = new ArrayList<>();

    public static void main(String[] args) throws InterruptedException {
        List<Integer> numbers = Numbers.GenerateNumber(NUMBER_COUNT);

        class Lowest {
            synchronized int getLowest(int index) {
                int lowestInArray = Integer.MAX_VALUE;
                for (int i = 0; i < splitArray[index].length; i++) {
                    if (splitArray[index][i] < lowestInArray) {
                        lowestInArray = splitArray[index][i];
                    }
                }
                return lowestInArray;
            }
        }

        Lowest lowest = new Lowest();

        class SelectionSortThread extends Thread {
            private int splitArrayIndex;

            private SelectionSortThread(int splitArrayIndex) {
                this.splitArrayIndex = splitArrayIndex;
            }

            public void run() {
                lowestNumbers.add(lowest.getLowest(splitArrayIndex));
            }
        }

        long startingTime = System.currentTimeMillis();

        for (int i = 0; i < NUMBER_COUNT; i++) {
            List<Thread> threads = new ArrayList<>();
            splitArray = fillSplitArray(availableProcessors, numbers);
            lowestNumbers.clear();

            for (int j = 0; j < availableProcessors; j++) {
                if(splitArray[j] != null) {
                    threads.add(new SelectionSortThread(j));
                }
            }

            for (Thread thread : threads) {
                thread.start();
            }

            for (Thread thread : threads) {
                thread.join();
            }

            int lowestInArray = getLowest(lowestNumbers);
            numbers = swap(numbers, lowestInArray);
            sortedList.add(numbers.get(0));
            numbers.remove(0);
        }

        System.out.println("Sorted list: " + Arrays.toString(sortedList.toArray()));
        System.out.println(System.currentTimeMillis() - startingTime);
    }

    private static int getLowest(List<Integer> lowestNumbers) {
        int lowestInArray = Integer.MAX_VALUE;
        for (Integer lowestNumber : lowestNumbers) {
            if (lowestNumber < lowestInArray) {
                lowestInArray = lowestNumber;
            }
        }
        return lowestInArray;
    }

    private static List<Integer> swap(List<Integer> list, int lowest)
    {
        int n = list.size();
        for(int i = 0; i < n; i++)
        {
            if(list.get(i) == lowest) {
                Collections.swap(list, 0, i);
                return list;
            }
        }
        return null;
    }



    static int[][] fillSplitArray(int arrayAmount, List<Integer> listToUse) {
        if (listToUse.size() == 0) {
            return new int[0][0];
        }

        int splitLength = (int) Math.ceil((double) listToUse.size() / (double) arrayAmount);
        int[][] splits = new int[arrayAmount][];

        int j = 0;
        int k = 0;
        for (int i = 0; i < listToUse.size(); i++) {
            if (k == splitLength) {
                k = 0;
                j++;
            }
            if (splits[j] == null) {
                int remainingNumbers = listToUse.size() - i;
                splits[j] = new int[Math.min(remainingNumbers, splitLength)];
            }
            splits[j][k++] = listToUse.get(i);
        }
        return splits;
    };
}

Numbers.java

import java.util.ArrayList;
import java.util.List;

class Numbers {
    static List<Integer> GenerateNumber(int numberCount) {
        List<Integer> temp = new ArrayList<>();
        for (int i = numberCount; i > 0; i--) {
            temp.add(i);
        }
        return temp;
    }
}

Есть ли что-то, что я делаю совершенно неправильно или что я могу улучшить?Я ожидаю, что параллельная реализация будет быстрее, чем последовательная, но пока это не так.В настоящее время это намного медленнее.

...