C# 此并行排序合并是否正确实现?

C# 此并行排序合并是否正确实现?,c#,multithreading,sorting,multicore,C#,Multithreading,Sorting,Multicore,此并行合并排序是否正确实现?它看起来是正确的,我花了40秒写了一个测试,它没有失败 它的要点是我每次都需要将数组分成两半进行排序。然后我试着确保我犯了错误并且(我自己的理智)。我想要一个简单的答案,但当我看到答案时,我觉得这是一种复杂的方式,所以我实现了下面的 当然,创建一个任务/线程来对一个4字节数组进行排序是没有意义的,但它需要学习线程。有什么不对劲的地方吗?或者我可以做些什么改变来让事情变得更好。对我来说,它看起来很完美,但我想得到一些一般性的反馈 static void Main(str

此并行合并排序是否正确实现?它看起来是正确的,我花了40秒写了一个测试,它没有失败

它的要点是我每次都需要将数组分成两半进行排序。然后我试着确保我犯了错误并且(我自己的理智)。我想要一个简单的答案,但当我看到答案时,我觉得这是一种复杂的方式,所以我实现了下面的

当然,创建一个任务/线程来对一个4字节数组进行排序是没有意义的,但它需要学习线程。有什么不对劲的地方吗?或者我可以做些什么改变来让事情变得更好。对我来说,它看起来很完美,但我想得到一些一般性的反馈

static void Main(string[] args)
{
    var start = DateTime.Now;
    //for (int z = 0; z < 1000000; z++)
    int z = 0;
    while(true)
    {
        var curr = DateTime.Now;
        if (curr - start > TimeSpan.FromMinutes(1))
            break;
        var arr = new byte[] { 5, 3, 1, 7, 8, 5, 3, 2, 6, 7, 9, 3, 2, 4, 2, 1 };
        Sort(arr, 0, arr.Length, new byte[arr.Length]);
        //Console.Write(BitConverter.ToString(arr));
        for (int i = 1; i < arr.Length; ++i)
        {
            if (arr[i] > arr[i])
            {
                System.Diagnostics.Debug.Assert(false);
                throw new Exception("Sort was incorrect " + BitConverter.ToString(arr));
            }
        }
        ++z;
    }
    Console.WriteLine("Tried {0} times with success", z);
}
static void Sort(byte[] arr, int leftPos, int rightPos, byte[] tempArr)
{
    var len = rightPos - leftPos;
    if (len < 2)
        return;
    if (len == 2)
    {
        if (arr[leftPos] > arr[leftPos + 1])
        {
            var t = arr[leftPos];
            arr[leftPos] = arr[leftPos + 1];
            arr[leftPos + 1] = t;
        }
        return;
    }
    var rStart = leftPos+len/2;
    var t1 = new Thread(delegate() { Sort(arr, leftPos, rStart, tempArr); });
    var t2 = new Thread(delegate() { Sort(arr, rStart, rightPos, tempArr); });
    t1.Start();
    t2.Start();
    t1.Join();
    t2.Join();
    var l = leftPos;
    var r = rStart;
    var z = leftPos;
    while (l<rStart && r<rightPos)
    {
        if (arr[l] < arr[r])
        {
            tempArr[z] = arr[l];
            l++;
        }
        else
        {
            tempArr[z] = arr[r];
            r++;
        }
        z++;
    }
    if (l < rStart)
        Array.Copy(arr, l, tempArr, z, rStart - l);
    else
        Array.Copy(arr, r, tempArr, z, rightPos - r);
    Array.Copy(tempArr, leftPos, arr, leftPos, rightPos - leftPos);
}
static void Main(字符串[]args)
{
var start=DateTime.Now;
//对于(int z=0;z<1000000;z++)
int z=0;
while(true)
{
var curr=DateTime.Now;
如果(当前-开始>时间跨度自分钟(1))
打破
var arr=新字节[]{5,3,1,7,8,5,3,2,6,7,9,3,2,4,2,1};
排序(arr,0,arr.Length,新字节[arr.Length]);
//Console.Write(位转换器.ToString(arr));
对于(int i=1;iarr[i])
{
System.Diagnostics.Debug.Assert(false);
抛出新异常(“排序不正确”+BitConverter.ToString(arr));
}
}
++z;
}
WriteLine(“成功尝试了{0}次”,z);
}
静态无效排序(字节[]arr,int-leftPos,int-righpos,字节[]tempArr)
{
var len=右位置-左位置;
if(len<2)
返回;
如果(len==2)
{
如果(arr[leftPos]>arr[leftPos+1])
{
var t=arr[leftPos];
arr[leftPos]=arr[leftPos+1];
arr[leftPos+1]=t;
}
返回;
}
var rStart=leftPos+len/2;
var t1=新线程(委托(){Sort(arr,leftPos,rStart,tempArr);});
var t2=新线程(委托(){Sort(arr,rStart,rightPos,tempArr);});
t1.Start();
t2.Start();
t1.Join();
t2.连接();
var l=左位;
var r=rStart;
var z=leftPos;

而(l您可以使用任务并行库来提供对线程和更干净代码的更好的抽象

除了使用TPL,您的代码的主要区别在于它有一个截止阈值,低于该阈值时,无论已启动的线程数是多少,都会使用顺序实现。这会阻止创建正在执行非常少量工作的线程。还有一个深度截止阈值,低于该阈值时不会创建新线程。这可以防止创建的线程数量超过硬件根据可用逻辑核的数量(Environment.ProcessCount)所能处理的线程数量

我建议在您的代码中实现这两种方法,以防止大型阵列的线程爆炸,并有效地创建线程,即使对于较小的阵列大小,这些线程也能完成非常小的工作量。这还将为您提供更好的性能

public static class Sort
{
    public static int Threshold = 150; 

    public static void InsertionSort(int[] array, int from, int to)
    {
        // ...
    }

    static void Swap(int[] array, int i, int j)
    {
        // ...
    }

    static int Partition(int[] array, int from, int to, int pivot)
    {
        // ...
    }

    public static void ParallelQuickSort(int[] array)
    {
       ParallelQuickSort(array, 0, array.Length, 
            (int) Math.Log(Environment.ProcessorCount, 2) + 4);
    }

    static void ParallelQuickSort(int[] array, int from, int to, int depthRemaining)
    {
        if (to - from <= Threshold)
        {
            InsertionSort(array, from, to);
        }
        else
        {
            int pivot = from + (to - from) / 2; // could be anything, use middle
            pivot = Partition(array, from, to, pivot);
            if (depthRemaining > 0)
            {
                Parallel.Invoke(
                    () => ParallelQuickSort(array, from, pivot, depthRemaining - 1),
                    () => ParallelQuickSort(array, pivot + 1, to, depthRemaining - 1));
            }
            else
            {
                ParallelQuickSort(array, from, pivot, 0);
                ParallelQuickSort(array, pivot + 1, to, 0);
            }
        }
    }
}
公共静态类排序
{
公共静态int阈值=150;
公共静态void InsertionSort(int[]数组、int-from、int-to)
{
// ...
}
静态无效交换(int[]数组,int i,int j)
{
// ...
}
静态int分区(int[]数组、int-from、int-to、int-pivot)
{
// ...
}
公共静态void并行快速排序(int[]数组)
{
ParallelQuickSort(数组,0,数组.Length,
(int)Math.Log(Environment.ProcessorCount,2)+4);
}
静态void ParallelQuickSort(int[]数组、int from、int to、int depth剩余)
{
如果(从0到-从0)
{
并行调用(
()=>ParallelQuickSort(数组、起始、透视、深度剩余-1),
()=>ParallelQuickSort(数组,pivot+1,to,depthLeving-1));
}
其他的
{
并行快速排序(数组、起始、透视、0);
并行快速排序(数组,pivot+1,to,0);
}
}
}
}
完整的源代码可在


你可以在

上阅读一篇关于实现的讨论,你的逻辑看起来是正确的。有没有理由怀疑这不会正常工作?除了这段代码,你还试过其他东西吗?@templatetypedef:没有,真的,我只是希望有人能告诉我一个好的做法或传统的方法来做这样的事情。我想你是怎么想的我们正在寻找的是;)