public static async Task <IList <TSource> > Sort <TSource>(IList <TSource> items, int begin, int end, int insertionSortCount, int threadCount, IComparer <TSource> comparer) { int insertionSortActionsCount = (int)Math.Ceiling((end - begin) / (double)insertionSortCount); int depth = (int)Math.Ceiling(Math.Log(insertionSortActionsCount, 2)); int donesCount = 0; IList <bool> dones = new bool[2 * insertionSortActionsCount + depth]; Queue <Action> queue = new Queue <Action>(); for (int i = begin; i < end; i += insertionSortCount) { int index = donesCount++; int insertionBegin = i; int insertionEnd = Math.Min(i + insertionSortCount, end); queue.Enqueue(() => InsertionSort(index, insertionBegin, insertionEnd)); } IList <TSource> items1 = items; IList <TSource> items2 = new TSource[items.Count]; for (int range = insertionSortCount; range < end - begin; range *= 2) { int lastActionsCount = (int)Math.Ceiling((end - begin) / (double)range); int lastActionsBegin = queue.Count - lastActionsCount; int currentRange = range; IList <TSource> src = items1, dest = items2; for (int j = 0, rangeBegin = begin; rangeBegin < end; j++, rangeBegin += range * 2) { int leftNodeIndex = lastActionsBegin + j * 2; int rightNodeIndex = lastActionsBegin + Math.Min(j * 2 + 1, lastActionsCount); int index = donesCount++; int currentBegin = rangeBegin; queue.Enqueue(() => Merge(leftNodeIndex, rightNodeIndex, index, src, dest, currentBegin, currentRange)); } StdUtils.Swap(ref items1, ref items2); } await AsyncUtils.ParallelForEach(queue, threadCount); return(items1); void InsertionSort(int thisIndex, int insertionSortBegin, int insertionSortEnd) { Linq.Sort.InsertionSort.Sort(items, insertionSortBegin, insertionSortEnd, comparer); lock (dones) { dones[thisIndex] = true; Monitor.PulseAll(dones); } } void Merge(int leftIndex, int rightIndex, int thisIndex, IList <TSource> mergeSrc, IList <TSource> mergeDest, int mergeBegin, int size) { lock (dones) { while (!dones[leftIndex]) { Monitor.Wait(dones); } while (!dones[rightIndex]) { Monitor.Wait(dones); } } MergeSort.Merge(mergeSrc, mergeDest, mergeBegin, size, end, comparer); lock (dones) { dones[thisIndex] = true; Monitor.PulseAll(dones); } } }