为什么函数调用需要这么多时间?

7 c# algorithm performance

我有以下插入排序算法实现:

private static void InsertionSort(List<int> array)
{
    for (int i = 1; i < array.Count; ++i)
    {
        for (int j = i; j > 0 && array[j - 1] > array[j]; --j)
        {
             //swap(array, j, j-1);

             int temp = array[j];
             array[j] = array[j-1];
             array[j-1] = temp;
        }
     }
}

private static void swap(List<int> array, int i, int j)
{
    int temp = array[i];
    array[i] = array[j];
    array[j] = temp;
}
Run Code Online (Sandbox Code Playgroud)

当我运行我的算法时,swap(array, j, j-1);它需要花费更多的时间(50000个元素+2秒),而不是我的函数体内联.

为什么?

Han*_*ant 15

手动内联方法没有错,只是没有必要.内联小方法是抖动执行的标准优化之一.这并不总是会发生,但在.NET 4.6.1中,x86和x64抖动在此示例代码中执行内联swap().而且,他们还展开内部循环以产生每次传递两次交换,这种手动优化程序员通常会跳过.

正确地对.NET应用程序进行基准测试并不总是那么直截了当. 运行程序的Release版本非常重要.并且使用调试器.虽然后者很容易修复,但请使用工具>选项>调试>常规>取消选中"抑制JIT优化"选项.没有充分的理由将其重新打开.

您现在还可以看到生成的机器代码,在InsertionSort()上设置断点以及何时命中使用Debug> Windows> Disassembly.倾向于让人们的眼睛流血,但很容易看到你得到两个内联交换().我会把你的汇编转储给你,只是看看吧.你应该清楚地看到测量的差异.这是我得到的:

使用x64上的50,000个随机整数的List上的swap()运行5次:

00:00:05.4447216
00:00:05.2928558
00:00:05.6960587
00:00:05.2835343
00:00:05.2809591
Run Code Online (Sandbox Code Playgroud)

相同的测试,但现在手工内联swap():

00:00:05.3015856
00:00:05.2877402
00:00:05.6369775
00:00:05.2603384
00:00:05.2616389
Run Code Online (Sandbox Code Playgroud)

需要尽可能长的时间.

我将无法显示List.Sort()得到的结果:

00:00:00.0075878
00:00:00.0073398
00:00:00.0076528
00:00:00.0078046
00:00:00.0066319
Run Code Online (Sandbox Code Playgroud)

  • 好吧,您现在知道区别的是,我链接的那些优化没有执行,因此您确实看到了方法调用的成本.它使用[内省排序](https://en.wikipedia.org/wiki/Introsort). (4认同)