简体   繁体   English

使用多线程进行合并排序

[英]Merge-sort using Multi-threading

I tried to parallelize merge-sort using multi-threading.Here is my code (please forgive if it poorly implemented.I did not care about the space-complexity of the program). 我尝试使用多线程并行化合并排序,这是我的代码(如果执行不当,请原谅,我不在乎程序的空间复杂性)。 I am achieving the sorted array.My question is:Will this process actually reduce the time taken to sort an array of large size?What all modifications are needed to make it efficient and is it o any use? 我正在实现排序数组。我的问题是:此过程是否会真正减少对大型数组进行排序所需的时间?需要进行哪些修改才能使其高效使用?

import java.io.IOException;
import java.util.Arrays;
import java.util.Random;
import java.util.Scanner;

public class Merge {
    public static int[] inputArray;
    public static int[] arr1;
    public static int[] arr2;
    public static int[] arr3;
    public static int t1_status=0;
    public static int t2_status=0;

    public static void main(String[] args) throws IOException{

        System.out.println("Enter the length of the array");

        Scanner in =new Scanner(System.in);

        int arraySize=in.nextInt();

        inputArray = new int[arraySize];

        Random rand=new Random();

        for(int i=0;i<arraySize;i++)
        {
            inputArray[i]=rand.nextInt(100);
        }

        //diving the original array into two subarrays

        arr1=Arrays.copyOfRange(inputArray, 0, inputArray.length/2);

        arr2=Arrays.copyOfRange(inputArray, (inputArray.length)/2,inputArray.length);
        //printing the original array
        System.out.print("The original array is array is ");

        for(int h:inputArray)
        {
            System.out.println(h);
        }

        Thread t1=new Thread(new Runnable(){
                public void run() 
                {
                    mergeSort(arr1);
                    System.out.println("t1 started");
                }

            });
        Thread t2=new Thread(new Runnable(){
                public void run()
                {
                    mergeSort(arr2);
                    System.out.println("t2 started");
                }

            });
        //starting threads
        t1.start();
        t2.start();

        try {
            t1.join();
            t2.join();
        }
        catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        if(t1.isAlive())
        {
            t1_status=1;
        }
        if(t2.isAlive())
        {
            t2_status=1;
        }
        t1.stop();
        t2.stop();

        arr3=new int[inputArray.length];

        merge(arr3,arr1,arr2);//merging arr1 and arr2.At this point both arr1 and arr2 are sorted.

        System.out.println("The sorted array is ");
        for(int m:arr3)
        {
            System.out.print(m);
            System.out.print(" ");
        }
        System.out.println(" ");
    }

    static void mergeSort(int[] A)
    {
        if (A.length > 1) 
        {
            int q = A.length/2;

            int[] leftArray = Arrays.copyOfRange(A, 0, q);
            int[] rightArray = Arrays.copyOfRange(A,q,A.length);
            mergeSort(leftArray);
            mergeSort(rightArray);
            merge(A,leftArray,rightArray);
        }
    }
    //merge function

    static void merge(int[] a, int[] l, int[] r) {
        int totElem = l.length + r.length;

        int i,li,ri;
        i = li = ri = 0;
        while ( i < totElem) {
            if ((li < l.length) && (ri<r.length)) {
                if (l[li] < r[ri]) {
                    a[i] = l[li];
                    i++;
                    li++;
                }
                else {
                    a[i] = r[ri];
                    i++;
                    ri++;
                }
            }
            else {
                if (li >= l.length) {
                    while (ri < r.length) {
                        a[i] = r[ri];
                        i++;
                        ri++;
                    }
                }
                if (ri >= r.length) {
                    while (li < l.length) {
                        a[i] = l[li];
                        li++;
                        i++;
                    }
                }
            }
        }

        if(t1_status==1){arr1=a;}
        else if(t2_status==1){arr2=a;}
        else{arr3=a;}
    }
}

Yes it can help, quite a bit depending on how many cores do you have and how big your array is. 是的,它可以提供帮助,这在很大程度上取决于您拥有多少个内核以及阵列的大小。 Spawning threads and coordinating work isn't free. 生成线程和协调工作不是免费的。 There's a soft spot on how many parallel threads are actually useful. 关于实际上有多少个并行线程有用的地方很柔和。

I think you're doing too little,but this is very easy to overdo: Since the process is CPU-bound you want one thread for each core. 我认为您做的太少了,但是这很容易过大:由于该进程受CPU限制,因此每个核心都需要一个线程。

A fixed thread pool/executor is handy here. 固定线程池/执行器在这里很方便。

Check out some example performance gains at CSE373:Data Structures and Algorithms/MergeSort . CSE373上查看一些性能提升的示例:数据结构和算法/ MergeSort

Sorting both halves in separate threads is a good start, but you can make use of parallelism through the merging, too. 将两个半部分分别放在单独的线程中是一个不错的开始,但是您也可以通过合并利用并行性。

Also, you should recurse do the subsorts in parallel, too... BUT keep track of the depth of recursion, and stop making new threads when you're already using all your cores. 另外,您也应该并行地并行执行子分类……但是要跟踪递归的深度,并在已经使用完所有内核时停止创建新线程。 Making new threads for those tiny little leaf sorts is a huge overhead. 为这些微小的小叶排序创建新线程是巨大的开销。

All together: 全部一起:

  1. Split into 2 threads 分为2个线程
  2. First, Thread 1 sorts the front half of the source array and Thread 2 sorts the back half of the source array. 首先,线程1对源数组的前半部分进行排序,线程2对源数组的后半部分进行排序。 To sort the haves, they either call this function recursively or switch to a serial sort if 2^recursion_depth > number_of_cores; 为了对富人进行排序,他们可以递归调用此函数,或者如果2 ^ recursion_depth> number_of_cores则切换为串行排序; then 然后
  3. Thread 1 does a forward merge of both halves into the front half of the destination, and Thread 2 does a backward merge of both halves into the back half of destination. 线程1将两个半部分都向前合并到目标的前半部分,线程2将两个半部分都向后合并到目标的后半部分。 They both stop when they reach the midpoint of the destination. 当它们到达目的地的中点时,它们都停止。

See the Collections.parallelSort() and the Fork/Join framework javadoc. 请参见Collections.parallelSort()和Fork / Join框架javadoc。

The small enough arrays are sorted as legacy on single thread, but when large enough (8192, I think), the parallelSort will divide and conquer, with the ForkJoinPool default pool (as many threads as there are cores). 足够小的数组在单线程上按旧排序,但是当足够大时(我认为是8192),parallelSort将使用ForkJoinPool默认池(与内核数量一样多的线程)进行分而治之。

Using only 2 threads is probably doubling your speed, but not more. 仅使用2个线程可能会使速度加倍,但不会更多。

FYI, the launcher thread should work too, not just sit there joining. 仅供参考,启动器线程也应该起作用,而不仅仅是坐在那里加入。 It can take the job of the 2nd thread for instance. 例如,它可以采用第二线程的工作。 Then only join once. 然后只加入一次。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM