Difference Between Invoke and DynamicInvoke
Asked Answered
P

1

164

What is the difference between Invoke and DynamicInvoke in delegates? Please give me some code example which explain difference between that two methods.

Phonologist answered 12/10, 2012 at 11:44 Comment(1)
If you have multicast delegates (calling multiple delegates contained in the invocation list), there is only .DynamicInvoke(args) available.Montane
G
249

When you have a delegate instance, you might know the exact type, or you might just know that it is a Delegate. If you know the exact type, you can use Invoke, which is very fast - everything is already pre-validated. For example:

Func<int,int> twice = x => x * 2;
int i = 3;
int j = twice.Invoke(i);
// or just:
int j = twice(i);

However! If you just know that it is Delegate, it has to resolve the parameters etc manually - this might involve unboxing, etc - a lot of reflection is going on. For example:

Delegate slowTwice = twice; // this is still the same delegate instance
object[] args = { i };
object result = slowTwice.DynamicInvoke(args);

Note I've written the args long hand to make it clear that an object[] is involved. There are lots of extra costs here:

  • the array
  • validating the passed arguments are a "fit" for the actual MethodInfo
  • unboxing etc as necessary
  • reflection-invoke
  • then the caller needs to do something to process the return value

Basically, avoid DynamicInvoke when-ever you can. Invoke is always preferable, unless all you have is a Delegate and an object[].

For a performance comparison, the following in release mode outside of the debugger (a console exe) prints:

Invoke: 19ms
DynamicInvoke: 3813ms

Code:

Func<int,int> twice = x => x * 2;
const int LOOP = 5000000; // 5M
var watch = Stopwatch.StartNew();
for (int i = 0; i < LOOP; i++)
{
    twice.Invoke(3);
}
watch.Stop();
Console.WriteLine("Invoke: {0}ms", watch.ElapsedMilliseconds);
watch = Stopwatch.StartNew();
for (int i = 0; i < LOOP; i++)
{
    twice.DynamicInvoke(3);
}
watch.Stop();
Console.WriteLine("DynamicInvoke: {0}ms", watch.ElapsedMilliseconds);
Guido answered 12/10, 2012 at 11:49 Comment(5)
Does it mean that in case of usage the DynamicInvoke compiler produce more IL code to handle delegate invocation?Phonologist
@Phonologist no, it'll use reflectionGuido
@MarcGravell when I try this in a method which is raising event, I am receiving first method call is taking around 0,7766 ms but second is taking around 0,0568 ms. When first one is Invoke it takes longer than DynamicInvoke or vice versa. When I tried your example with 1 loop and look at ms Invoke: 0,0478ms, DynamicInvoke: 0,053ms . Why are you comparing them more than 1 call? And why the first one takes longer than second call of function?Sinusoid
@Sinusoid The first call to the method causes JIT compilation to take place by the CLR--this applies to any method on the first time it's called after the process is started. In this sort of scenario, you can do one of three things: (1) run the method several times so that the time it took for the first call becomes insignificant in the final result, (2) don't start measuring until after you've called the method once, or (3) use ngen.exe (overkill). This post explains it well enough... #4446703Indoor
@marc-gravell You don't need to create an array to pass to DynamicInvoke since it's method signature states the params keyword for the args parameter.Salmi

© 2022 - 2024 — McMap. All rights reserved.