【问题标题】:C#: Why is a function call faster than manual inlining?C#:为什么函数调用比手动内联更快?
【发布时间】:2013-03-14 18:50:36
【问题描述】:

我测量了两种计算 2 的幂的方法的执行时间:

1) 内联

result = b * b;

2) 通过简单的函数调用

result = Power(b);

在调试模式下运行时,一切都按预期进行:调用函数比在线计算要昂贵得多(在线 385 毫秒对 570 毫秒函数调用)。

在发布模式下,我希望编译器能够大大加快函数调用的执行时间,因为编译器会在内部内联非常小的 Power() 函数。但我不希望函数调用比手动内联计算更快。

最令人惊讶的是:在发布版本中,第一次运行需要 109 毫秒,而调用 Power() 的第二次运行只需要 62 毫秒。

函数调用如何比手动内联更快?

这是你的复制程序:

class Program
{
    static void Main(string[] args)
    {
        Console.WriteLine("Starting Test");

        // 1. Calculating inline without function call
        Stopwatch sw = Stopwatch.StartNew();

        for (double d = 0; d < 100000000; d++)
        {
            double res = d * d;
        }

        sw.Stop();
        Console.WriteLine("Checked: " + sw.ElapsedMilliseconds);

        // 2. Calulating power with function call
        Stopwatch sw2 = Stopwatch.StartNew();

        for (int d = 0; d < 100000000; d++)
        {
            double res = Power(d);
        }

        sw2.Stop();
        Console.WriteLine("Function: " + sw2.ElapsedMilliseconds);

        Console.ReadKey();
    }

    static double Power(double d)
    {
        return d * d;
    }
}

【问题讨论】:

  • 你在调试器(F5)下启动程序了吗?在这种情况下,优化被抑制了。
  • 您是在发布模式下运行生成的 .exe 还是在 VS 中运行?另外,您是否尝试过以不同的顺序调用它们?我发现这会产生微妙的差异
  • 那么,为什么使用 int 作为双精度比使用双精度更快?
  • @Vercas:很可能是因为递增和比较双精度值更昂贵。
  • @DanielHilgarth 啊,好点...

标签: c# performance release inline inline-code


【解决方案1】:

你的测试是错误的。在第二部分中,您使用 int d 而不是双精度。也许它解释了时差。

【讨论】:

  • 函数一的运行时间在我的电脑上总是比内联的慢(不管是int还是double)。
  • 修复后的结果如何?
  • @RobertNiestroj:结果见我的回答。
【解决方案2】:

正如 Xavier 正确发现的那样,您在一个循环中使用 double 并在另一个循环中使用 int。将两者更改为相同的类型将使结果相同 - 我测试过。

此外:您在这里真正衡量的是添加和比较的持续时间。您没有测量d 的平方的持续时间,因为它根本没有发生:在发布版本中,优化器完全删除了循环体,因为没有使用结果。您可以通过注释掉循环体来确认这一点。持续时间相同。

【讨论】:

  • 也完全正确。这是我的错误。我已经监督了 int
【解决方案3】:

Daniel Hilgarth 是对的,因为未使用结果,所以根本没有进行计算(在调试模式下可能不是这种情况)。试试下面的例子,你会得到正确的结果:

static void Main(string[] args)
    {
        Console.WriteLine("Starting Test");
        var list = new List<int>();
        // 1. Calculating inline without function call
        Stopwatch sw = Stopwatch.StartNew();

        for (int d = 0; d < 100000000; d++)
        {
            int res = d * d;
            list.Add(res);
        }

        sw.Stop();
        Console.WriteLine("Checked: " + sw.ElapsedMilliseconds);
        // 2. Calulating power with function call

        list = new List<int>();
        Stopwatch sw2 = Stopwatch.StartNew();

        for (int d = 0; d < 100000000; d++)
        {
            int res = Power(d);
            list.Add(res);
        }

        sw2.Stop();
        Console.WriteLine("Function: " + sw2.ElapsedMilliseconds);

        Console.ReadKey();
    }

【讨论】:

  • 这段代码不会抛出OverflowException,因为res 在这些循环中最终会超过Int32.MaxValue 吗?
猜你喜欢
  • 2011-04-30
  • 2013-05-17
  • 1970-01-01
  • 1970-01-01
  • 2014-08-01
  • 1970-01-01
  • 2018-05-23
  • 2018-08-19
  • 1970-01-01
相关资源
最近更新 更多