在C#4.0 b1,dynamic的出现得到了很多人的关注,该关键字的出现能大幅改进某些情况下的开发效率,但是,通过大家对比测试,该方式同时也会带来很大的性能损失,方法的执行不过是对反射执行的封装,远不如使用Emit或者Expression编译委托来得快.但是在最新的C# 4.0 beta2,dynamic的实现的得到了很大的改变.

    首先使用测试程序对比下几种常见的方法调用.程序分别将对直接调用,传统反射调用,dynamic调用,expression调用,emit调用速度进行简单的对比,该对比程序只调用一个空方法,纯测试方法调用的耗时,如果测试有什么问题,欢迎提出.

    下面给出测试主程序的源代码(完整代码见文后附带源码):

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;

namespace DynamicTest {
    
class Program {
        
static void Main(string[] args) {
            TestClass staticInstanse 
= new TestClass();
            dynamic dynamicInstanse 
= staticInstanse;
            
int num = 100000//次数
            var expressionFun = staticInstanse.GetExpressionCallFunction("TestMethod");
            var emitFun 
= staticInstanse.GetEmitCallFunction("TestMethod");
            var method 
= staticInstanse.GetType().GetMethod("TestMethod");
            Console.WriteLine(
"开始对比测试(连续执行{0}次空方法):", num);
            Stopwatch watch 
= new Stopwatch();
            
//测试直接调用
            watch.Start();
            
for (int i = 0; i < num; i++) {
                staticInstanse.TestMethod();
            }
            watch.Stop();
            Console.WriteLine(
"直接调用耗时:{0} ms", watch.Elapsed.TotalMilliseconds);
            
//测试反射调用
            watch.Reset();
            watch.Start();
            
for (int i = 0; i < num; i++) {
                method.Invoke(staticInstanse, 
null);
            }
            watch.Stop();
            Console.WriteLine(
"使用反射调用耗时:{0} ms", watch.Elapsed.TotalMilliseconds);
            
//测试包含首次调用的dynamic调用
            watch.Reset();
            watch.Start();
            
for (int i = 0; i < num; i++) {
                dynamicInstanse.TestMethod();
            }
            watch.Stop();
            Console.WriteLine(
"使用包含首次调用的dynamic调用耗时:{0} ms", watch.Elapsed.TotalMilliseconds);
            
//测试出去首次调用后的dynamic调用
            watch.Reset();
            watch.Start();
            
for (int i = 0; i < num; i++) {
                dynamicInstanse.TestMethod();
            }
            watch.Stop();
            Console.WriteLine(
"使用去掉首次调用的dynamic调用耗时:{0} ms", watch.Elapsed.TotalMilliseconds);
            
//测试expression调用
            watch.Reset();
            watch.Start();
            
for (int i = 0; i < num; i++) {
                expressionFun(staticInstanse);
            }
            watch.Stop();
            Console.WriteLine(
"使用Expression调用耗时:{0} ms", watch.Elapsed.TotalMilliseconds);
            
//测试emit调用
            watch.Reset();
            watch.Start();
            
for (int i = 0; i < num; i++) {
                emitFun(staticInstanse);
            }
            watch.Stop();
            Console.WriteLine(
"使用Emit调用耗时:{0} ms", watch.Elapsed.TotalMilliseconds);
        }
    }
}

 

    通过测试,最后得到的结果如下(测试结果进代表本人机器测试结果,其他机器可能会有不同,但是相信相对的的速度对比值应该一致):

 

    通过测试可以得到以下的大致结果:

    直接调用最快

    使用emit调用其次,大概是直接调用的10倍左右

     Expression调用再次,然后是dynamic调用,不过很明显,dynamic的第一次调用速度比较慢,去掉第一次的执行之后,dynamic已经和expression调用的时间相差不大,当然最慢的是传统反射调用,远远低于其他的调用方式.

    在此可以看出,dynamic的实现相比b1中得到了极大的改善,已经能满足绝大多数使用情况.

    我们可以通过Reflector来查看目前dynamic的实现方式:

    很明显,dynamic不再是传统的反射调用,个人猜测也是采用通过某种方式编译成委托的方式进行调用,所以能使得性能得到了极大的提高.

     测试程序完整源代码下载:/Files/leven/DynamicTest.rar

posted on 2009-10-23 17:29  Leven  阅读(2877)  评论(11编辑  收藏  举报
CopyRight 2008, Leven's Blog xhtml | css
Leven的个人Blog