c# - 为什么函数调用要花这么多时间?

标签 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;
}

当我使用 swap(array, j, j-1); 运行我的算法时,它比我使用内联函数主体花费更多的时间(50000 个元素 +2 秒)。

为什么?

最佳答案

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

正确地对 .NET 应用程序进行基准测试并不总是那么简单。 非常对于运行程序的发布版本非常重要。并使用调试器。尽管后者很容易修复,请使用工具 > 选项 > 调试 > 常规 > 取消选中“抑制 JIT 优化”选项。没有充分的理由将其重新打开。

您现在还可以看到生成的机器代码,在 InsertionSort() 上设置断点,当它命中时使用 Debug > Windows > Disassembly。往往让人眼睛流血,但很容易看出你得到了两个内联的 swap()。我会把程序集转储留给你,看一看。你应该清楚地看到测量的差异。这是我得到的:

在 x64 上使用 swap() 在具有 50,000 个随机整数的列表上运行它 5 次:

00:00:05.4447216
00:00:05.2928558
00:00:05.6960587
00:00:05.2835343
00:00:05.2809591

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

00:00:05.3015856
00:00:05.2877402
00:00:05.6369775
00:00:05.2603384
00:00:05.2616389

需要尽可能长的时间。

如果不显示使用 List.Sort() 得到的结果,我会失职:

00:00:00.0075878
00:00:00.0073398
00:00:00.0076528
00:00:00.0078046
00:00:00.0066319

关于c# - 为什么函数调用要花这么多时间?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37632161/

相关文章:

c# - 使用 ADO.NET 的批处理操作

C# 只读与获取

c# - 我可以使用 .net 检查电子邮件地址是否存在吗?

Python 文件预处理(将列从离散值范围转换为连续值范围。)

java - 使用 try-catch over if 条件以在 java 中以最小的性能影响安全地设置值

c# - 在 C# 中加速 SOAP 请求

algorithm - 如何优化 Knuth Morris Pratt 字符串匹配算法

algorithm - Knuth-Morris-Pratt 算法中的前缀函数计算

Eclipse 与 Netbeans 基准测试

algorithm - 最小生成树的运行时间? (原始方法)