昨天我们比较了Array.Sort<T>方法与LINQ排序的性能,知道了LINQ排序的性能以较大幅度落后 于Array.Sort<T>方法。而对于Array.Sort<T>来说,性能最高的是其中使用 Comparer<int>.Default作为比较器的重载方法。在前文的末尾我们做出了推测:由于排序算法已 经近乎一个标准了(快速排序),因此从算法角度来说,Array.Sort<T>方法和LINQ排序上不应该 有那么大的差距,因此造成两者性能差异的原因,应该是具体实现方式上的问题。
下载.NET框架的代码
既然是比较实现的区别,那么阅读代码是很直接的选择。谈到阅读.NET代码,我们往往会使用.NET Reflector将框架的程序集反编译为C#代码——不排除有朋友喜欢观察IL,并认为它们更直接,更底层。 不过我倒觉得在绝大部分情况下,IL能看出的东西从C#也能看出,而C#无法了解的IL也帮不上忙,因此许 多“由IL发现问题”的文章其实只是自己和自己在爽。
不过,虽然.NET Reflector将程序集反编译成非常优秀的C#代码,但是还是无法恢复之前的不少信息 。例如,局部变量名无法得知,这就给理解代码意图造成了困难。再例如,为了可读性我们可能会将一些 条件语句分开写,而C#编译器则可能把它们连做一块儿。至于注释等明显会被去除的东西就更不用说了。 因此,在能直接读到代码的情况下,我并不倾向于使用.NET Reflector。
您可能会说:这不是废话么,不过有些类库——如.NET框架并没有提供源代码,这又有什么办法呢? 其实微软也已经公布了.NET框架相当部分程序集的源代码(几乎所有v2.0的程序集,如 mscrolib, System,System.Web等等),而且它们其实都可以使用NetMassDownloader直接下载到本地。随员代码发 布的还有方便调试的pdb文件,不过这是另一个话题了,我们现在只关心源代码。
因此,我建议您将所有微软提供的源代码都下载到本地。在看不懂.NET Reflector的反编译结果时, 不妨参考一下源代码——还是包含注释的源代码。
Array.Sort<T>方法实现
各Array.Sort<T>方法的重载最终都会委托给下面这个重载来执行:
public static void Sort<T>(T[] array, int index, int length, IComparer<T> comparer)
{
...
if (length > 1)
{
// <STRIP>
// TrySZSort is still faster than the generic implementation.
// The reason is Int32.CompareTo is still expensive than just using "<" or ">".
// </STRIP>
if (comparer == null || comparer == Comparer<T>.Default)
{
if (TrySZSort(array, null, index, index + length - 1))
{
return;
}
}
ArraySortHelper<T>.Default.Sort(array, index, length, comparer);
}
}