1

I read this post and I tried to do the same but I came across a very strange behavior when comparing the del.DynamicINvoke(args) Vs. del(args)

Update

So after Jon and usr comments i post now new working code.

I'll really appreciate any help!

Code:

using System;
using System.Diagnostic;
using System.Threading;

namespace DynamicInvokeVsInvoke {
  public class Program {
    static void Main(string[] args) {
      var objArgs = new object[] {100, 1.2345678 };
      Action<int, double> a = (i, d) => {};
      Action<object[]> action = o => a((int)o[0], (double)o[1]);
      var sw = new Stopwatch();
      sw.Start();
      for (int i = 0; i < 1000; i++)
         a.DynamicInvoke(objArgs);
      Console.WriteLine("Dynamic: " + sw.ElapsedMilliseconds);
      sw.Stop();
      sw = new Stopwatch();
      sw.Start();
      for (int i = 0; i < 1000; i++)
         action(objArgs);
      Console.WriteLine("Invoke: " + sw.ElapsedMilliseconds);
      sw.Stop();
    }
  }
}

Results:

When 'a' is empty method and the loop runs 1000000 times the DynamicInvoke took approximately 4000 ms and the direct Invoke took 20 ms

When i'm put in a Thread.Sleep(20) and the loop runs 1000 times then the DynamicInvoke and the direct Invoke took approximately 20 seconds

p.s. i can't copy/paste from vs for some reason so i write the code manually if you see syntax error please let me know

Community
  • 1
  • 1
Maya
  • 959
  • 4
  • 11
  • 18
  • 1
    You're not comparing `del.Invoke` with `del.DynamicInvoke`. The delegate you're invoking directly has an extra level of "wrapping" around it. It doesn't explain all the results, but it is a discrepancy between your description and your code. – Jon Skeet Jul 16 '12 at 05:56
  • @Jon I'm understand but still why if i compare it with empty method the wrapping is about 200 faster then the dynamicinvoke and if the method cobtains body the results changed – Maya Jul 16 '12 at 06:42
  • No idea. It's not at all clear why you're using an event or a static initializer in the first place though. Why don't you just have the delegate as a local variable? Your code is unnecessarily complicated at the moment. – Jon Skeet Jul 16 '12 at 07:13
  • @Jon you right i did it for some reason. I'll edit the code later (im from my mobile now) but i did the comprasion without all the unnecessarily complicated and i got the same strange behavior. – Maya Jul 16 '12 at 07:23
  • @JonSkeet I edited my code please check it if you can. thanks! – Maya Jul 16 '12 at 13:07
  • Your code doesn't compile for many many reasons. Asking us to explain performance on code that doesn't compile is... unhelpful. – Marc Gravell Jul 16 '12 at 22:20
  • @Marc narc im sorry this is because i write it in the post and dont copy it from vs. I try to read it again and fix it. – Maya Jul 17 '12 at 04:26
  • @Marc Marc i edited my code in vs to make it work and updated the post but for some reason i dont see the update. Anyway i edited now again without vs and im pretty sure its work now. So if you can... Thanks – Maya Jul 17 '12 at 06:11

2 Answers2

1

First thing to note: when looking at performance always ensure you are running a release/optimized build, and run it without the IDE attached. You can usually get away with ctrl+f5 in Visual Studio, but if in doubt: run it from the command line.

When 'a' is empty method and the loop runs 1000000 times the DynamicInvoke took approximately 4000 ms and the direct Invoke took 20 ms

Fair enough; I get 2729ms for DynamicInvoke and 8ms for direct invoke; but that is what we expect; we know that DynamicInvoke is slower. But everything here is as we expect. In fact, if we correct for the fact that Invoke is unfairly running an extra level of delegate invoke (which we should expect to roughly-double the time taken), we get:

static void Main()
{
    int x = 100;
    double y = 1.2345678;
    var objArgs = new object[] { x, y };
    Action<int, double> a = (i, d) => { };
    var sw = new Stopwatch();
    sw.Start();
    const int loop = 1000000;
    for (int i = 0; i < loop; i++)
        a.DynamicInvoke(objArgs);
    Console.WriteLine("Dynamic: " + sw.ElapsedMilliseconds);
    sw.Stop();
    sw = new Stopwatch();
    sw.Start();
    for (int i = 0; i < loop; i++)
        a(x,y);
    Console.WriteLine("Invoke: " + sw.ElapsedMilliseconds);
    sw.Stop();
}

with results:

Dynamic: 2785
Invoke: 3

So far, nothing unexpected.

When i'm put in a Thread.Sleep(20) and the loop runs 1000 times then the DynamicInvoke and the direct Invoke took approximately 20 seconds

Yep, 20ms x 1000 is definitely 20 seconds. The 20ms sleep time is not exact; we expect some variance around that number, which adds up when multiplied by 1000. In particular, the sleep interrupt isn't going to fire for every single CPU cycle, so we should probably expect the slightly irregular sleep cycle to eat up the difference between a Invoke and DynamicInvoke (about 2.75 microseconds per call).

Changing loop to 1000 and adding a Thread.Sleep(20) I get:

Dynamic: 20395
Invoke: 20370

Again, nothing surprising here. In fact, with the slight randomness introduced by a Thread.Sleep(), multiplied by 1000 I would find it perfectly acceptable if Invoke occasionally took longer than Dynamic.

I see nothing in the least bit surprising in the numbers.

Marc Gravell
  • 927,783
  • 236
  • 2,422
  • 2,784
  • Thanks for the answer and for the explantion. I tried to put body in the method but not Thread.Sleep() (calculate some values creating list anf dictionary add them objects and get them some checks etc.) and then if i call it once the results are 273ms to Dynamic and 211ms to Invoke, if i call it 10 times the Dynamic is 1773ms and the Invoke is 1682ms so far no surprise but if i call it 100 times the Dynamic is 18387ms and the Invoke is 18946! and it without the randomness introduced by a Thread.Sleep(). how can i measure if Invoke is really faster in the real application? Thanks again! – Maya Jul 17 '12 at 09:01
  • @Maya by timing ;p Actually, there is no question to answer there: it *is* faster. The question is: is the performance difference *important* for your application. If you don't have a performance issue currently, then the answer is "probably not" – Marc Gravell Jul 17 '12 at 11:39
  • yes its very important, right now all my events fired dynamicly and i have alot of them (hundreds of thousands). anyway i'll change it to Invoke. thanks for the help! – Maya Jul 17 '12 at 15:15
0

There is something in your measurement setup that is producing a systematic error. Surely your wouldn't think that using DynamicInvoke makes the body of the delegate being invoked faster. It has no impact on the body.

usr
  • 162,013
  • 33
  • 219
  • 345
  • 10k dynamic invoke calls probably don't take 4.2sec. There is still something wrong. If you post a self-contained repro I'll take a look. – usr Jul 15 '12 at 14:49
  • what do you mean self contained repro? – Maya Jul 16 '12 at 09:24
  • A program that I can paste into an empty console application and press F5 to run it. – usr Jul 16 '12 at 10:17