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

标签 c# performance interface

我在 .NET 中发现了这种奇怪的行为,甚至在查看了 CLR via C# 之后也是如此我还是很困惑。假设我们有一个带有一个方法的接口(interface)和一个实现它的类:

interface IFoo
{
    void Do();
}

class TheFoo : IFoo
{
    public void Do()
    {
        //do nothing
    }
}

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

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);

令人惊讶的是(至少对我而言)耗时相差大约 10%:

Elapsed time: 6005
Elapsed time: 6667

差别不大,所以在大多数情况下我不会太担心这一点。但是,即使查看了 IL 代码,我还是无法弄清楚为什么会发生这种情况,所以如果有人指出我明显缺少的东西,我将不胜感激。

最佳答案

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

检查 this answer有关抖动执行的常见优化列表。请注意该答案中提到的有关分析的警告。

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

关于C#:为什么类变量调用实现的接口(interface)方法比接口(interface)变量更快?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6396362/

相关文章:

c# - 使用 Spring .NET 将依赖项注入(inject) MVC Controller

c# - 来自 WaterfallStep Dialog MS Bot 框架 v4 的自适应卡片响应

performance - GLSL:为什么本地数组中的随机写入比循环写入慢得多?

以包含接口(interface)对象的数组作为参数的 Java 方法

c# - 防止在 xamarin 和 monodroid 中旋转后重新加载 Activity

c# - 使用 Webclient 获取对 url 的请求会抛出异常,但如果在浏览器中打开它则工作正常

python - 执行 pygame 时提高性能?

java - `public/protected/private` 关键字对性能有影响吗?

java - Scala 无法解析继承的 Java 接口(interface)常量成员

C# 接口(interface) - 用不同的签名实现