DynamicInvoke和Invoke的奇怪行为

时间:2012-07-15 13:28:02

标签: c# performance reflection delegates dynamic-invoke

我阅读了this帖子,我尝试做同样的事情但是在比较del.DynamicINvoke(args)V时我遇到了一个非常奇怪的行为。德尔(参数)

更新

所以在Jon和usr评论之后我发布了新的工作代码。

我真的很感激任何帮助!

代码:

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();
    }
  }
}

结果:

当'a'为空方法并且循环运行1000000次时,DynamicInvoke大约需要4000毫秒,直接调用需要20毫秒

当我放入Thread.Sleep(20)并且循环运行1000次时,DynamicInvoke和直接调用大约需要20秒

P.S。我出于某种原因无法从vs复制/粘贴所以我手动编写代码如果你看到语法错误请告诉我

2 个答案:

答案 0 :(得分:1)

首先要注意的是:在查看性能时,请始终确保您正在运行发布/优化版本,然后运行而不使用 IDE。您通常可以在Visual Studio中使用 ctrl + f5 ,但如果有疑问:从命令行运行它。

  

当'a'为空方法并且循环运行1000000次时,DynamicInvoke大约需要4000毫秒,直接调用需要20毫秒

足够公平; DynamicInvoke获得2729ms,直接调用获得8ms;但这就是我们所期望的;我们知道 DynamicInvoke速度较慢。但是这里的一切都如我们所料。事实上,如果我们纠正Invoke不公平地运行委托调用的额外级别这一事实(我们应该将所需的时间大致加倍),我们得到:

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();
}

结果:

Dynamic: 2785
Invoke: 3

到目前为止,没有任何意外。

  

当我放入Thread.Sleep(20)并且循环运行1000次时,DynamicInvoke和直接调用大约需要20秒

是的,20ms x 1000绝对是20秒。 20毫秒的睡眠时间并不准确;我们期望在该数字周围出现一些差异,当乘以1000时会增加。特别是,睡眠中断不会在每个CPU周期中触发,所以我们应该期待稍微不规则的睡眠周期吃掉InvokeDynamicInvoke之间的差异(每次通话大约2.75微秒)。

loop更改为1000并添加Thread.Sleep(20)我得到:

Dynamic: 20395
Invoke: 20370

再一次,这里没什么可惊讶的。实际上,由于Thread.Sleep()引入的轻微随机性乘以1000,如果Invoke偶尔花费的时间超过Dynamic,我会觉得完全可以接受。

在数字中我没有看到任何令人惊讶的东西。

答案 1 :(得分:0)

您的测量设置中存在一些产生系统错误的信息。当然,您不会认为使用DynamicInvoke会更快地调用委托的 body 。它对身体没有影响。