C# 4.0 Beta2改进之全新的dynamic

    在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不再是传统的反射调用,个人猜测也是采用通过某种方式编译成委托的方式进行调用,所以能使得性能得到了极大的提高.

     测试程序完整源代码下载:
下载文件点击下载此文件

文章来自: 本站原创
引用通告: 查看所有引用 | 我要引用此文章
Tags: c#  dynamic 
评论: 0 | 引用: 0 | 查看次数: 2095
发表评论
用户名:
密 码: 游客发言不需要密码.
验证码: 验证码
内 容:
选 项:
虽然发表评论不用注册,但是为了保护您的发言权,建议您注册帐号.
字数限制 500 字 | HTML代码允许 关闭 | 评论可修改 关闭