根据这个问题-Pass Method as Parameter using C#和我的一些个人经验,我想了解更多关于在C#中调用委托与只调用方法的性能.

虽然委托非常方便,但我有一个通过委托进行大量回调的应用程序,当我们重写此应用程序以使用回调接口时,速度提高了一个数量级.这是在.NET2.0中出现的,所以我不确定在3和4中情况发生了什么变化.

如何在编译器/CLR内部处理对委托的调用,以及这如何影响方法调用的性能?


EDIT-澄清我所说的委托与回调接口是什么意思.

对于异步调用,我的类可以提供调用者可以订阅的OnComplete事件和关联的委托.

或者,我可以使用调用方实现的OnComplete方法创建一个ICallback接口,然后向类注册自己,该类将在完成时调用该方法(即Java处理这些事情的方式).

推荐答案

我还没有看到这种效果——我当然从来没有遇到过瓶颈.

下面是一个非常粗略且现成的基准测试,它显示(无论如何在我的盒子上)代理实际上比接口多faster个:

using System;
using System.Diagnostics;

interface IFoo
{
    int Foo(int x);
}

class Program : IFoo
{
    const int Iterations = 1000000000;

    public int Foo(int x)
    {
        return x * 3;
    }

    static void Main(string[] args)
    {
        int x = 3;
        IFoo ifoo = new Program();
        Func<int, int> del = ifoo.Foo;
        // Make sure everything's JITted:
        ifoo.Foo(3);
        del(3);

        Stopwatch sw = Stopwatch.StartNew();        
        for (int i = 0; i < Iterations; i++)
        {
            x = ifoo.Foo(x);
        }
        sw.Stop();
        Console.WriteLine("Interface: {0}", sw.ElapsedMilliseconds);

        x = 3;
        sw = Stopwatch.StartNew();        
        for (int i = 0; i < Iterations; i++)
        {
            x = del(x);
        }
        sw.Stop();
        Console.WriteLine("Delegate: {0}", sw.ElapsedMilliseconds);
    }
}

结果(.NET 3.5;.NET 4.0b2大致相同):

Interface: 5068
Delegate: 4404

现在我并不特别相信这意味着代理比接口快really个...但这让我相当确信,它们并没有慢一个数量级.此外,在委托/接口方法中,这几乎不起任何作用.显然,随着每次调用所做的工作越来越多,调用成本的影响将越来越小.

需要注意的一点是,在只使用单个接口实例的情况下,不要多次创建新委托.这could会引发一个问题,因为它会引发垃圾收集等.如果在循环中使用实例方法作为委托,您会发现在循环外声明委托变量、创建单个委托实例并重用它更有效.例如:

Func<int, int> del = myInstance.MyMethod;
for (int i = 0; i < 100000; i++)
{
    MethodTakingFunc(del);
}

比以下各项更高效:

for (int i = 0; i < 100000; i++)
{
    MethodTakingFunc(myInstance.MyMethod);
}

这会不会就是你看到的问题?

.net相关问答推荐

尽管有`disable`注释,但未 suppress Pylint语法错误

ASP.NET核心最小API必须以正斜杠开头吗?

将 Span 传递到函数时出现 F# 错误

如何计算给定2个字符串的距离相似性度量?

是否有任何 x 次的 for 循环的更短/更简单的版本?

指定的版本字符串不符合要求的格式 - major[.minor[.build[.revision]]]

简单委托(委托)与多播委托

获取 .NET Framework 目录路径

如何退出所有正在运行的线程?

从 Windows 窗体打开 URL

为什么 System.Timers.Timer 能在 GC 中存活,而 System.Threading.Timer 不能?

System.Speech.Recognition 和 Microsoft.Speech.Recognition 有什么区别?

POCO 是什么意思?

.Net 中 AOP 的最佳实现是什么?

强制 XmlSerializer 将 DateTime 序列化为 'YYYY-MM-DD hh:mm:ss'

我应该如何删除 DbSet 中的所有元素?

从 'System.Int32' 到 'System.Nullable`1[[System.Int32, mscorlib]] 的无效转换

如何向 C# Winforms 中的标签添加提示或工具提示?

在不使用while循环的情况下找到最里面的异常?

枚举和匹配属性的 C# 命名约定