c#:为什么函数调用比手工内联快?
本文关键字:为什么 函数调用 | 更新日期: 2023-09-27 18:05:46
我测量了计算2的幂的两种方法的执行时间:
1)内联
result = b * b;
2)使用一个简单的函数调用
result = Power(b);
在调试模式下运行时,一切都如预期的那样:调用函数比在行中进行计算要昂贵得多(行中385毫秒vs.函数调用570毫秒)。
在发布模式下,我希望编译器能够大大加快函数调用的执行时间,因为编译器会在内部内联非常小的Power()
函数。但是我不希望函数调用比手动内联计算快。
最令人惊讶的情况是:在发布版本中,第一次运行需要109 ms,第二次运行调用Power()
只需要62 ms。
函数调用如何比手动内联更快?
这是你复制的程序:
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;
}
}
你的测试是错误的。在第二部分中,您使用int d
而不是双精度。也许这可以解释时差。
正如Xavier正确发现的那样,您在一个循环中使用double而在另一个循环中使用int。将两者更改为相同的类型将使结果相同-我测试了它。
更进一步:你在这里真正衡量的是添加和比较的持续时间。您没有测量d
平方的持续时间,因为它根本没有发生:在发布版本中,优化器完全删除了循环体,因为没有使用结果。您可以通过注释掉循环体来确认这一点。
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();
}