直接调用、委托与反射调用的性能区别

      今天做了这么一个试验:
      将直接调用、委托与反射调用放在一起,测试了一下性能。同时也发现了一些认识上的误区。测试类如下:
     public   delegate   void  PlusOneDelegate(SampleForTest obj);
    
public   delegate   void  StandPlusOneDelegate();
    
public   class  SampleForTest
    {
        
public   int  Value;
        
public   virtual   void  PlusOne()
        {
            Value
++ ;
        }
    }

      测试代码如下:
         public   void  PerformanceTest()
        {
            
int  times  =   1000000 ;
            SampleForTest sample 
=   new  SampleForTest();
            Stopwatch sw 
=   new  Stopwatch();
            Console.WriteLine(
" Following test is repeat {0} times " , times);

            sw.Start();
            
for  ( int  i  =   0 ; i  <  times; i ++ ) ;
            sw.Stop();
            Console.WriteLine(
" Basic loop takes {0}ms " , sw.ElapsedMilliseconds);

            sw.Reset();

            sw.Start();
            
for  ( int  i  =   0 ; i  <  times; i ++ )
                sample.PlusOne();
            sw.Stop();
            Console.WriteLine(
" Direct call takes {0}ms " , sw.ElapsedMilliseconds);

            sw.Reset();
            sample.Value 
=   0 ;

            sw.Start();
            PlusOneDelegate d 
=  Delegate.CreateDelegate( typeof (PlusOneDelegate),
                
typeof (SampleForTest).GetMethod( " PlusOne " ))  as  PlusOneDelegate;
            
object [] args  =   new   object [] { sample };
            
for  ( int  i  =   0 ; i  <  times; i ++ )
                d.DynamicInvoke(args);
            sw.Stop();
            Console.WriteLine(
" delegate dynamic invoke takes {0}ms " , sw.ElapsedMilliseconds);
            Assert.AreEqual(times, sample.Value);

            sw.Reset();
            sample.Value 
=   0 ;

            sw.Start();
            PlusOneDelegate d2 
=  Delegate.CreateDelegate( typeof (PlusOneDelegate),
                
typeof (SampleForTest).GetMethod( " PlusOne " ))  as  PlusOneDelegate;
            
for  ( int  i  =   0 ; i  <  times; i ++ )
                d2(sample);
            sw.Stop();
            Console.WriteLine(
" delegate takes {0}ms " , sw.ElapsedMilliseconds);
            Assert.AreEqual(times, sample.Value);

            sw.Reset();
            sample.Value 
=   0 ;

            sw.Start();
            StandPlusOneDelegate d3 
=   new  StandPlusOneDelegate(sample.PlusOne);
            
for  ( int  i  =   0 ; i  <  times; i ++ )
                d3();
            sw.Stop();
            Console.WriteLine(
" stand delegate takes {0}ms " , sw.ElapsedMilliseconds);
            Assert.AreEqual(times, sample.Value);

            sw.Reset();
            sample.Value 
=   0 ;

            sw.Start();
            System.Reflection.MethodInfo mi 
=   typeof (SampleForTest).GetMethod( " PlusOne " );
            
object [] args2  =   new   object [ 0 ];
            
for  ( int  i  =   0 ; i  <  times; i ++ )
                mi.Invoke(sample, args2);
            sw.Stop();
            Console.WriteLine(
" reflection invoke takes {0}ms " , sw.ElapsedMilliseconds);
            Assert.AreEqual(times, sample.Value);

        }

      其中分别测试了循环本身的代价、直接调用的代价、Delegate的DynamicInvoke的代价、CreateDelegate产生的Delegate的代价、标准写出来的Delegate的代价和反射后Invoke的代价。
      结果如下:
Following test is repeat 1000000 times
Basic loop takes 3ms
Direct call takes 10ms
delegate dynamic invoke takes 7603ms
delegate takes 12ms
stand delegate takes 11ms
reflection invoke takes 2207ms
      循环本身消耗3ms,直接调用消耗10ms,减去3ms的循环代价,就是7ms(因为虚方法不能被JIT Inline),委托的DynamicInvoke方法的代价出奇的高,用CreateDelegate获得的委托与标准的委托相差不大(可以认为是误差),与直接调用的代价非常接近。最后,本来以为反射的代价应该是最高的,却意外的发现,虽然代价确实很高,但是还是比DynamicInvoke的性能要好。
      结论代价是:直接调用<委托标准调用<<反射调用<委托DynamicInvoke调用
      1、可以看出委托的标准调用是在知道方法签名的前提下最灵活的性能最好的调用方式。
      2、反射调用在不知道方法签名的前提下提供较好的性能(可以结合Emit获得更好的性能)
      3、委托DynamicInvoke的性能最差,尽量不要使用
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值