2012-07-15 53 views
1

我读0123'后,我试图做同样的事情,但我在比较del.DynamicINvoke(args)VS时遇到了一个非常奇怪的行为。德尔(参数)DynamicInvoke和Invoke的奇怪行为

更新

所以之后乔恩和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' 是空的方法和循环运行百万倍DynamicInvoke需要大约4000毫秒和直接调用了20毫秒

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

p.s.我无法从vs复制/粘贴出于某种原因,所以我手动编写代码如果您看到语法错误,请让我知道

+1

你没有比较'del.Invoke'和'del.DynamicInvoke'。您直接调用的代理具有额外的“包装”级别。它没有解释所有的结果,但它是描述和你的代码之间的差异。 – 2012-07-16 05:56:38

+0

@Jon我很明白,但仍然为什么如果我将它与空方法比较,包装约200更快然后dynamicinvoke,如果方法cobtains身体结果改变 – Maya 2012-07-16 06:42:11

+0

不知道。尽管如此,为什么你使用事件或静态初始化器还不是很清楚。你为什么不把委托作为局部变量?您的代码目前不必要的复杂。 – 2012-07-16 07:13:54

回答

1

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

当“a”是空的方法和循环运行百万倍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秒

是的,20毫秒×1000绝对是20秒。20ms的睡眠时间不准确;我们预计该数字会有一些变化,当乘以1000时会相加。特别是,睡眠中断不会在每个CPU周期触发,所以我们可能应该会在睡眠周期稍微不规律的时候吃掉InvokeDynamicInvoke之间的差异(每次通话约2.75微秒)。

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

Dynamic: 20395 
Invoke: 20370 

再次,没什么希奇这里。实际上,由Thread.Sleep()引入的轻微随机性乘以1000,如果Invoke偶尔花费比Dynamic更长,我会发现它是完全可以接受的。

我在数字中没有看到任何惊奇之处。

+0

感谢您的答复和解释。我试图把体内的方法,但没有Thread.Sleep()(计算一些值创建列表和anf字典添加他们的对象,并得到他们一些检查等),然后如果我叫它一旦结果是273ms动态和211ms到调用,如果我称它为动态的10倍1773ms和调用是1682ms到目前为止并不意外,但如果我把它称为动态的100倍动态是18387ms和调用是18946!并且它没有Thread.Sleep()引入的随机性。我如何测量Invoke在实际应用中真的更快?再次感谢! – Maya 2012-07-17 09:01:43

+0

@Maya by timing; p实际上,这里没有问题可以回答:它*更快。问题是:您的应用程序的性能差异*重要*。如果你目前没有任何性能问题,那么答案是“可能不是” – 2012-07-17 11:39:03

+0

是的,它非常重要,现在我所有的事件都是动态激发的,我有很多(数十万)事件。无论如何,我会将其更改为Invoke。谢谢您的帮助! – Maya 2012-07-17 15:15:53

0

您的测量设置中有某些内容会产生系统错误。当然你不会认为使用DynamicInvoke会使委托的正文被调用得更快。它对身体没有影响。

+0

请检查我的更新 – Maya 2012-07-15 14:27:56

+0

10K动态调用调用可能不需要4.2秒。还有一些错误。如果你发布一个独立的repro,我会看看。 – usr 2012-07-15 14:49:43

+0

你是什么意思自包含repro? – Maya 2012-07-16 09:24:21