C#:为什么函数调用比手动内联更快?
我测量了计算2的幂的两种方法的执行时间: 1)内联C#:为什么函数调用比手动内联更快?,c#,performance,release,inline,inline-code,C#,Performance,Release,Inline,Inline Code,我测量了计算2的幂的两种方法的执行时间: 1)内联 result = b * b; 2)通过简单的函数调用 result = Power(b); 在调试模式下运行时,一切都如预期的那样:调用一个函数比在线计算要昂贵得多(在线385毫秒,而在线570毫秒函数调用) 在发布模式下,我希望编译器能大大加快函数调用的执行速度,因为编译器会在内部内联非常小的Power()函数。但我不希望函数调用比手动内联计算更快 最令人惊讶的是,在发布版本中,第一次运行需要109毫秒,第二次运行调用Power()只需
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;
}
}
类程序
{
静态void Main(字符串[]参数)
{
控制台写入线(“启动测试”);
//1.在不调用函数的情况下计算内联
秒表sw=Stopwatch.StartNew();
对于(双d=0;d<100000000;d++)
{
双精度=d*d;
}
sw.Stop();
控制台写入线(“选中:+sw.ElapsedMilliseconds”);
//2.使用函数调用计算功率
Stopwatch sw2=Stopwatch.StartNew();
对于(int d=0;d<100000000;d++)
{
双res=功率(d);
}
sw2.Stop();
Console.WriteLine(“函数:+sw2.ElapsedMilliseconds”);
Console.ReadKey();
}
静态双电源(双d)
{
返回d*d;
}
}
您的测试错误。在第二部分中,使用intd
而不是double。也许这可以解释时差。正如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();
}
static void Main(字符串[]args)
{
控制台写入线(“启动测试”);
var list=新列表();
//1.在不调用函数的情况下计算内联
秒表sw=Stopwatch.StartNew();
对于(int d=0;d<100000000;d++)
{
int res=d*d;
列表。添加(res);
}
sw.Stop();
控制台写入线(“选中:+sw.ElapsedMilliseconds”);
//2.使用函数调用计算功率
列表=新列表();
Stopwatch sw2=Stopwatch.StartNew();
对于(int d=0;d<100000000;d++)
{
int res=功率(d);
列表。添加(res);
}
sw2.Stop();
Console.WriteLine(“函数:+sw2.ElapsedMilliseconds”);
Console.ReadKey();
}
您是否在调试器(F5)下启动了程序?在这种情况下,优化被抑制。您是在发布模式下运行生成的.exe还是在VS中运行的?还有,你试过按不同的顺序给他们打电话吗?我发现这有一个微妙的区别。那么,为什么使用int作为double比使用double快呢?@Vercas:很可能是因为递增和比较double更昂贵。@DanielHilgarth啊,好的一点……在我的计算机上,函数一的运行时间总是比内联函数慢(无论是int还是double).修复后的结果是什么?@RobertNiestroj:请看我的答案,也完全正确。这是我的错误。我曾经监督过INT,这段代码是否会抛出一个OverflowException
,因为res
最终会在这些循环中远远超过Int32.MaxValue
?