您的位置: 飞扬精品软件园 >> 文章中心 >> 网络通讯 >> 网络应用 >> 拓展动态编程的新领域

相关文章链接

最新新闻资讯

    拓展动态编程的新领域

    拓展动态编程的新领域


    • 阅览次数: 文章来源: 原文作者: 整理日期: 2010-08-29


    中文MSDN将CallSite<T>译为“动态(调用)站点”,它是DLR中的核心组件之一。

    动态站点对象通过CallSite<T>.Create()方法创建, C#编译器会为其指定一个派生自CallSiteBinder的对象(称为“动态站点绑定对象”)作为其参数。

    动态站点绑定对象是与具体语言相关的,比如IronPython和C#都有各自的动态站点绑定对象。

    动态站点绑定对象的主要工作是将代码中的动态表达式(本例中为d++)转换为一棵“抽象语法树(AST:Abstract Syntax Tree)”,这棵语法树被称为“DLR Tree”,是在.NET 3.5所引入的LINQ表达式树的基础上扩充而来的,因此,有时又称其为“表达式树(Expression Tree)”

    DLR在内部调用此表达式树的Compile()方法生成IL指令,得到一个可以被CLR所执行的委托(在本例中其类型就是Func<CallSite, object, object>)。

    动态调用站点对象(本例中为<>p__Site1)有一个Target属性,它负责引用这一生成好的委托。

    委托生成之后,动态表达式的执行就体现为委托的执行,其实参由C#编译器直接“写死”在IL代码中。

    简化的代码示意如下(通过Reflector得到,为便于阅读,修改了变量名):

    object d = 100;
        object CS$0$0000 = d;
        if (<>p__Site1 == null)
            <>p__Site1 = CallSite<Func<CallSite, object, object>>.Create(……);
        d = <>p__Site1.Target(<>p__Site1, CS$0$0000);

    上述类型推断、方法绑定及IL代码生成的工作都是在程序运行时完成的。

    (4)动态代码很慢吗?

    动态编程语言易学易用,代码紧凑,开发灵活,但性能则一直是它的“软肋”。为了提升性能,DLR设计了一个三级缓存策略。

    动态站点绑定对象会为动态调用表达式转换而成的语法树加上相应的测试条件(称为“test”),构成一个“规则(Rule)”,这个规则可以用于判断某个语法树是否可用于特定的动态调用表达式。

    举个例子,请看以下这个动态表达式:

    d1 + d2

    如果在程序运行时d1和d2都是int类型的整数,则DLR生成的规则为:

    if( d1 is int && d2 is int) //测试条件
            return (int)d1+(int)d2;  //语法树

    DLR通过检查规则中的“测试条件”,就可以知道某个动态表达式是否可以使用此规则所包容的语法树。

    “规则”是DLR缓存的主要对象。

    前面介绍过的动态站点对象Target属性所引用的委托是第一级缓存,它实现的处理逻辑是这样的:

    //当前处理规则,属于第1级缓存
        if( d1 is int && d2 is int)  //测试条件
            return (int)d1+(int)d2; //满足测试条件,直接返回一个表达式树
        //未命中,则在第2级、第3级缓存中查找,如果找到了,用找到的结果更新第1级缓存
        return site.Update(site,d1,d2);

    如果3级缓存中都没有命中的规则,则此动态站点所关联的调用站点绑定对象会尝试创建一个新的规则。如果创建新规则失败,则由当前编程语言(比如C#)所提供的默认调用站点绑定对象决定如何处理,通常的作法是抛出一个异常。

    当前版本的DLR第2级缓存了10条规则,第3级则缓存了100条规则。

    由于DLR自身设计了一个“规则”缓存系统,又充分利用了CLR所提供的JIT缓存(因为所有动态调用代码最终都会转换为CLR可以执行的IL指令,而CLR可以缓存这些代码),使得动态代码仅仅在第一次执行时性能较差,后续的连续调用其性能可以逼近静态代码。

    [1] [2] [3] [4] [5] [6]


查看所有评论

网友对拓展动态编程的新领域 的评论

网名:
主题:
内容:
验证码: