呼吁与会代表VS方法的性能性能、代表、方法、VS

2023-09-02 11:45:38 作者:此生只与你白头到老

下面这个问题 - http://stackoverflow.com/questions/2082615/pass-method-as-parameter-using-c和一些我个人的经验,我想知道多一点有关调用委托VS打电话只是在C#中方法的性能。

Following this question - http://stackoverflow.com/questions/2082615/pass-method-as-parameter-using-c and some of my personal experience I'd like to know a little more about the performance of calling a delegate vs just calling a method in C#.

虽然与会代表都非常方便,我有一个应用程序,通过做大量的委托回调,当我们重写了该用的回调接口,我们得到了级的速度提高一个数量级。这与.NET 2.0,所以我不知道事情是如何与3和4改变了。

Although delegates are extremely convenient, I had an app that did lots of callbacks via delegates and when we rewrote this to use callback interfaces we got an order of magnitude speed improvement. This was with .NET 2.0 so I'm not sure how things have changed with 3 and 4.

是如何调用编译器/ CLR内部处理代表这又如何影响方法调用性能?

How are calls to delegates handled internally in the compiler/CLR and how does this affect performance of method calls?

修改 - 要澄清我的意思是代表VS回调接口

EDIT - To clarify what I mean by delegates vs callback interfaces.

对于异步调用我的类可以提供一个onComplete时间和相关的委托调用者可以订阅。

For asynchronous calls my class could provide an OnComplete event and associated delegate which the caller could subscribe to.

另外,我可以创建具有的onComplete方法调用者工具,然后将其自身注册的类,然后调用完成该方法的ICallback接口(即Java的方式处理这些事情)。

Alternatively I could create an ICallback interface with an OnComplete method that the caller implements and then registers itself with the class that will then call that method on completion (i.e. the way Java handles these things).

推荐答案

我还没有看到这种效果 - 我从未遇到过这是一个瓶颈

I haven't seen that effect - I've certainly never encountered it being a bottleneck.

下面是一个非常粗糙和准备基准,这显示(在我的箱子反正)代表实际上是更快的不是接口:

Here's a very rough-and-ready benchmark which shows (on my box anyway) delegates actually being faster than interfaces:

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是差不多的):

Results (.NET 3.5; .NET 4.0b2 is about the same):

Interface: 5068
Delegate: 4404

现在我没有特别的信心,这意味着代表们的真正的不是接口速度更快...但它让我相当确信,他们不是幅度较慢的订单。此外,这是做委托/接口方法中几乎没有。显然,调用成本将会使越来越少的区别,你做的每个呼叫越来越多的工作。

Now I don't have particular faith that that means delegates are really faster than interfaces... but it makes me fairly convinced that they're not an order of magnitude slower. Additionally, this is doing almost nothing within the delegate/interface method. Obviously the invocation cost is going to make less and less difference as you do more and more work per call.

有一点要注意的是,你不能创建一个新的委托几次,你会只使用一个单一的接口实例。这的可以的会引起问题,因为它会引发垃圾回收等,如果您使用的是实例方法作为循环中的代表,你会发现它更有效地循环外声明的委托变量,创建一个单一的委托实例,然后重新使用。例如:

One thing to be careful of is that you're not creating a new delegate several times where you'd only use a single interface instance. This could cause an issue as it would provoke garbage collection etc. If you're using an instance method as a delegate within a loop, you will find it more efficient to declare the delegate variable outside the loop, create a single delegate instance and reuse it. For example:

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

更有效率比:

is more efficient than:

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

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

Could this have been the problem you were seeing?