Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Performance of calling delegates vs methods

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

like image 615
Paolo Avatar asked Jan 17 '10 21:01

Paolo


People also ask

Why use delegates over methods?

Delegates allow methods to be passed as parameters. Delegates can be used to define callback methods. Delegates can be chained together; for example, multiple methods can be called on a single event. Methods don't have to match the delegate type exactly.

Which is faster to execute delegate or interface?

Delegates are faster because they are only a pointer to a method. Interfaces need to use a v-table to then find a delegate; They are equal, but delegates are easier to use.

Why delegates why not call methods directly?

If you think of delegates as being similar to interface definitions for a specific type of method, you can start to see why delegates exist. They allow clients of our delegates to ignore all the details of their implementations - even their names!

What is difference between delegate and method?

A Delegate is an object which refers to a method or you can say it is a reference type variable that can hold a reference to the methods. Delegates in C# are similar to the function pointer in C/C++.


2 Answers

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?

like image 152
Jon Skeet Avatar answered Sep 28 '22 15:09

Jon Skeet


I find it completely implausible that a delegate is substantially faster or slower than a virtual method. If anything the delegate should be negligibly faster. At a lower level, delegates are usually implemented something like (using C-style notation, but please forgive any minor syntax errors as this is just an illustration):

struct Delegate {     void* contextPointer;   // What class instance does this reference?     void* functionPointer;  // What method does this reference? } 

Calling a delegate works something like:

struct Delegate myDelegate = somethingThatReturnsDelegate(); // Call the delegate in de-sugared C-style notation. ReturnType returnValue =      (*((FunctionType) *myDelegate.functionPointer))(myDelegate.contextPointer); 

A class, translated to C, would be something like:

struct SomeClass {     void** vtable;        // Array of pointers to functions.     SomeType someMember;  // Member variables. } 

To call a vritual function, you would do the following:

struct SomeClass *myClass = someFunctionThatReturnsMyClassPointer(); // Call the virtual function residing in the second slot of the vtable. void* funcPtr = (myClass -> vtbl)[1]; ReturnType returnValue = (*((FunctionType) funcPtr))(myClass); 

They're basically the same, except that when using virtual functions you go through an extra layer of indirection to get the function pointer. However, this extra indirection layer is often free because modern CPU branch predictors will guess the address of the function pointer and speculatively execute its target in parallel with looking up the address of the function. I've found (albeit in D, not C#) that virtual function calls in a tight loop are not any slower than non-inlined direct calls, provided that for any given run of the loop they're always resolving to the same real function.

like image 42
dsimcha Avatar answered Sep 28 '22 16:09

dsimcha