C#:为什么调用实现的接口方法对于类变量比对接口变量更快?

Ale*_*kov 15 c# performance interface

我在.NET中发现了这种奇怪的行为,甚至在通过C#再次查看CLR之后我仍然感到困惑.让我们假设我们有一个接口,一个方法和一个实现它的类:

interface IFoo
{
    void Do();
}

class TheFoo : IFoo
{
    public void Do()
    {
        //do nothing
    }
}
Run Code Online (Sandbox Code Playgroud)

然后我们只想实例化这个类并以两种方式多次调用这个Do()方法:使用具体的类变量和使用接口变量:

TheFoo foo1 = new TheFoo();

Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
for (long i = 0; i < 1000000000; i++)
    foo1.Do();
stopwatch.Stop();
Console.Out.WriteLine("Elapsed time: " + stopwatch.ElapsedMilliseconds);

IFoo foo2 = foo1;

stopwatch = new Stopwatch();
stopwatch.Start();
for (long i = 0; i < 1000000000; i++)
    foo2.Do();
stopwatch.Stop();
Console.Out.WriteLine("Elapsed time: " + stopwatch.ElapsedMilliseconds);
Run Code Online (Sandbox Code Playgroud)

令人惊讶的是(至少对我而言)经过的时间差异大约为10%:

Elapsed time: 6005
Elapsed time: 6667
Run Code Online (Sandbox Code Playgroud)

差别不是很大,所以在大多数情况下我不会担心这个问题.然而,我甚至无法弄清楚为什么即使在查看IL代码后也会发生这种情况,所以如果有人指出我明显缺少的东西,我将不胜感激.

Han*_*ant 18

你必须查看机器代码才能看到发生了什么.当你这样做时,你会看到抖动优化器已经完全删除了对foo1.Do()的调用.像这样的小方法被优化器内联.由于该方法的主体不包含代码,因此根本不生成机器代码.它无法在接口调用上进行相同的优化,对于反向工程,接口方法指针实际指向空方法并不够智能.

请查看此答案,以获取抖动执行的常见优化列表.请注意该答案中提到的有关分析的警告.

注意:查看发布版本中的机器代码需要更改选项.默认情况下,即使在发布版本中,也会在调试代码时禁用优化程序.工具+选项,调试,常规,取消勾选"在模块加载时抑制JIT优化".