并行快速排序
快速排序的基本思想:通过一轮排序使得数组“基本有序”,“基本有序”的意思是指以数组中数某下标的数为准,左边的数小于此数,右边的数大小此数,从而将数组分成两个待排序的数组。通过递归最终完成整个数组的排序。
从快速排序的基本思想可以得出以下结论:
通过一次排序分成2个待排序数组
通过二次排序分成4个待排序数组
……
通过n次排序分成2^n个待排序数组
假设CPU有N个Core(Intel CPU的核数通常是2的x次幂,AMD不一定),那么log2N次排序后就可以进行并行化操作,将N个数组分别放到N个Core中进行计算,如下图所示

下面是并行快速排序跟非并行快速排序的比较:

上图是在Intel Q83004-Core CPU 上运行的结果,可以发现多核并行节省了快速排序的时间,但效果并不显著。
其主要原因在于:快速排序通常所选的Key是数组的第一个元素,通过一轮排序后分成的两个数组大小通常不相同(几乎不可能相同)。
最差情况下并行将退化成串行。
附测试源代码:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Diagnostics; namespace SortLib { public class ParallelQuickSort:QuickSort { int coreNum = 4; int pardepth = 0; public int CoreNum { get { return coreNum; } set { coreNum = value; pardepth = depth(value); } } public ParallelQuickSort(TestData _data) : base(_data) { } private static int depth(int core) { int depth = 0; while ((core = core / 2) > 0) depth++; return depth; } public override void DoSort() { Stopwatch sw = new Stopwatch(); sw.Start(); quickSort(0, data.Len - 1,0); sw.Start(); onFinished(this, new SortEventArgs(sw.ElapsedMilliseconds)); //base.DoSort(); } List<Action> pActions = new List<Action>(); public void quickSort(int start, int end, int depth) { if (start < end) { int pos = getKeyPos(start, end); if (depth == pardepth&&depth!=0)//此处并行 { sortUnit s1 = new sortUnit(this,start, pos - 1,depth+1); sortUnit s2 = new sortUnit(this, pos + 1, end, depth + 1); pActions.Add(new Action(s1.run)); pActions.Add(new Action(s2.run)); if (pActions.Count == (1<<pardepth)) { System.Threading.Tasks.Parallel.Invoke(pActions.ToArray()); } } else { quickSort(start, pos - 1,depth+1); quickSort(pos + 1, end,depth + 1); } } } } public class sortUnit { public ParallelQuickSort sorter; public int start; public int end; public int depth; public sortUnit(ParallelQuickSort sort, int _start, int _end, int _depth) { this.start = _start; this.end = _end; this.depth = _depth; this.sorter = sort; } private void sort() { } public void run() { sorter.quickSort(start, end, depth); } } } public class TestData:ICloneable { int len; private int[] data;// = new int[1000]; public int Len { get { return len; } set { len = value; } } public int[] Data { get { return data; } set { data = value; } } public void GenRandomData() { Random rd = new Random((int)DateTime.Now.Ticks); for (int i = 0; i < len; i++) { data[i] = rd.Next(int.MaxValue); } } public TestData(int _len) { this.len = _len; data = new int[len]; } public object Clone() { TestData newData = new TestData(this.len); newData.len = this.len; this.data.CopyTo(newData.data, 0); return newData; } } int MB = 1024*1024; SortLib.TestData data; public Form1() { InitializeComponent(); int len = 5 * MB; data = new SortLib.TestData(len); data.GenRandomData(); } private void button2_Click(object sender, EventArgs e) { SortLib.TestData newdata = (SortLib.TestData)data.Clone(); SortLib.ParallelQuickSort srt = new SortLib.ParallelQuickSort(newdata); srt.CoreNum = (int)numericUpDown1.Value; srt.Finished += new SortLib.SortFinished(srt_Finished); srt.DoSort(); }

浙公网安备 33010602011771号