问题描述
关于这个问题 - ,其中一些我个人的经验,我想了解一些关于调用代理的表现,而不是在C#中调用一个方法。
尽管代表非常方便,一个通过代表进行大量回调的应用程序,当我们重写这个来使用回调接口时,我们得到了一个数量级的改进。这是.NET 2.0,所以我不知道3和4中的事情发生了变化。
如何在编译器/ CLR内部对委托进行调用,以及如何这是否会影响方法调用的执行?
编辑 - 澄清代表的意思vs回调接口。
对于异步调用,我的类可以提供一个OnComplete事件和关联的委托,呼叫者可以订阅它。或者,我可以使用调用者实现的OnComplete方法创建一个ICallback接口,然后注册自己的类,然后在完成时调用该方法(即Java的方式
我没有看到这个效果 - 我一直从来没有遇到过瓶颈。 / p>
这是一个非常粗糙且准备好的基准,它显示(在我的框上)代表实际上比接口更快地
using System;
使用System.Diagnostics;
接口IFoo
{
int Foo(int x);
}
class程序: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;
//确保一切都是JITted:
ifoo.Foo(3);
del(3)
秒表sw = Stopwatch.StartNew(); (int i = 0; i< Iterations; i ++)
{
x = ifoo.Foo(x);
}
sw.Stop();
Console.WriteLine(Interface:{0},sw.ElapsedMilliseconds);
x = 3;
sw = Stopwatch.StartNew(); (int i = 0; i< Iterations; i ++)
{
x = del(x);
}
sw.Stop();
Console.WriteLine(Delegate:{0},sw.ElapsedMilliseconds);
}
}
结果(.NET 3.5; .NET 4.0b2是大约相同):
界面:5068
代表:4404
现在我没有什么特别的信念,这意味着代理人真的比接口更快,但它让我相当相信它们不是一个数量级的更慢。此外,这在代理/接口方法中几乎没有任何内容。显然,调用费用会越来越少地变化,因为您每次呼叫都会做更多的工作。
要注意的一件事是,您不会创建一个新的代表几次,你只能使用一个单一的接口实例。这个可能会导致一个问题,因为它会引发垃圾回收等。如果您在一个循环中使用一个实例方法作为委托,您将发现在循环之外声明委托变量更有效率,创建一个委托实例并重新使用它。例如:
Func< int,int> del = myInstance.MyMethod; (int i = 0; i
{
MethodTakingFunc(del);
}
效率比:
$ b $ (int i = 0; i {
MethodTakingFunc(myInstance.MyMethod); b
}
这可能是您看到的问题吗?
Following this question - 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#.
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.
How are calls to delegates handled internally in the compiler/CLR and how does this affect performance of method calls?
EDIT - To clarify what I mean by delegates vs callback interfaces.
For asynchronous calls my class could provide an OnComplete event and associated delegate which the caller could subscribe to.
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);
}
}
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?
这篇关于调用代表与方法的性能的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!