【发布时间】:2012-03-22 08:14:48
【问题描述】:
我最近在 C# 中实现了一个快速排序算法。对包含数百万个项目的整数数组进行排序,代码的性能大约比 .NET 的实现低 10%。
private static void QS(int[] arr, int left, int right)
{
if (left >= right) return;
var pIndex = Partition(arr, left, right);
QS( arr, left, pIndex);
QS( arr, pIndex + 1, right);
}
在包含 500 万个项目的数组上,此代码比 .NET 慢约 60 毫秒。
随后,我创建了另一个方法,该方法将Partition() 方法内联到QS() 中(消除了方法调用和return 语句)。然而,这导致性能下降到比 .NET 的排序方法慢约 250 毫秒。
为什么会这样?
编辑: 这是Partition() 方法的代码。在QS() 的内联版本中,除了return 语句之外,该方法的全部内容替换了var pIndex = Partition(arr, left, right); 行。
private static int Partition(int[] arr, int left, int right)
{
int pivot = arr[left];
int leftPoint = left - 1;
int pIndex = right + 1;
int temp = 0;
while (true)
{
do { pIndex--; } while (arr[pIndex] > pivot);
do { leftPoint++; } while (arr[leftPoint] < pivot);
if (leftPoint < pIndex)
{
temp = arr[leftPoint];
arr[leftPoint] = arr[pIndex];
arr[pIndex] = temp;
}
else { break; }
}
return pIndex;
}
编辑#2: 如果有人对编译感兴趣,这里是调用算法的代码:
编辑#3: Haymo 建议的新测试代码。
private static void Main(string[] args)
{
const int globalRuns = 10;
const int localRuns = 1000;
var source = Enumerable.Range(1, 200000).OrderBy(n => Guid.NewGuid()).ToArray();
var a = new int[source.Length];
int start, end, total;
for (int z = 0; z < globalRuns; z++)
{
Console.WriteLine("Run #{0}", z+1);
total = 0;
for (int i = 0; i < localRuns; i++)
{
Array.Copy(source, a, source.Length);
start = Environment.TickCount;
Array.Sort(a);
end = Environment.TickCount;
total += end - start;
}
Console.WriteLine("{0}\t\tTtl: {1}ms\tAvg: {2}ms", ".NET", total, total / localRuns);
total = 0;
for (int i = 0; i < localRuns; i++)
{
Array.Copy(source, a, source.Length);
start = Environment.TickCount;
Quicksort.SortInline(a);
end = Environment.TickCount;
total += end - start;
}
Console.WriteLine("{0}\t\tTtl: {1}ms\tAvg: {2}ms", "Inlined", total, total / localRuns);
total = 0;
for (int i = 0; i < localRuns; i++)
{
Array.Copy(source, a, source.Length);
start = Environment.TickCount;
Quicksort.SortNonInline(a);
end = Environment.TickCount;
total += end - start;
}
Console.WriteLine("{0}\tTtl: {1}ms\tAvg: {2}ms\n", "Not inlined", total, total / localRuns);
}
}
【问题讨论】:
-
你能提供一个可编译的例子吗?
-
能否发布您使用的完整代码,包括您用来测量时间的代码?
-
即时优化器已经内联方法。它可以做出比您更好的决策,它实际上知道机器代码是什么样的,并且可以判断内联是真正的优化还是只会导致代码膨胀。真正的优化是让代码更智能。优化 QS 有很好的记录,初学者只需查看 Wikipedia 文章。
-
测量是使用
Stopwatch实例进行的。Stopwatch实例在调用QS()之前立即启动,并在QS()调用之后的行上停止。我将其更改为使用Environment.TickCount,但无论如何他们给出了相同的结果。 -
.NET 快速排序有一个内联(并且相当智能)的分区方法。它还使用 IComparable 方法进行所有比较,这可能会增加开销,但这可能会通过分区步骤中使用的算法得到缓解。
标签: c# performance inline quicksort