• 2007-05-23

    用Ruby编写builtin

    版权声明:转载时请以超链接形式标明文章原始出处和作者信息及本声明
    http://www.blogbus.com/dreamhead-logs/5487713.html

    或许你已经知道了,XRuby在用Ruby编写builtin

    XRuby很早就开始用Ruby编写builtin,甚至在我加入XRuby的时候就是这个样子了。在这个问题上,比XRuby走得更远的是rubinius,这个项目中用Ruby所写的builtin的比例比XRuby要大得多,事实上,XRuby从中借鉴了不少东西。

    其实,我对用Ruby去写builtin一直有一些质疑,我所能接受的这么做的主要原因是因为这么写来得简单。问题在那呢?我一直以为用Ruby编写builtin性能会很差,因为解释Ruby脚本是需要成本的。所以,我和一些人谈到这个问题时,总会说用Ruby写builtin只是过渡方案,之后可能会回到Java上。直到最近,我才发现,自己的思路有问题。因为XRuby的builtin是预先编译好的,也就是说,解析builtin的成本都在XRuby的构建过程中,所以,在XRuby执行的过程中,用Ruby写成的builtin和用Java写成的builtin本质上没有任何区别,性能上不会有任何损失。这种做法的好处源自预处理,对于编译器产生的代码而言,编译的过程就是运行过程的预处理。其实,解释器也可以做到这一点,比如Python,它会将前面解析的产物(.pyc文件)保留下来,减少运行时处理的内容。但是,目前的C Ruby实现没有这么做,Ruby的脚本必须每次都要经过解析器处理,所以,如果同样用Ruby的builtin,目前的C Ruby实现会比较惨。当然,就成本而言,编译器前端的成本在整个计算中所占的比例往往是很小的,但是,如果没有这个成本,那会更美妙的。

    当然,这并不是说用Ruby编写builtin就完美无缺了。生成代码能否像手工编写的那样简洁,如果不能的话,那就意味着生成的.class文件会有一些冗余在里面。不过,我对这个问题倒是没有太多顾虑,因为编译器是XRuby主要的成果物,所以,这个问题真的是问题了,我们完全可以通过自己的努力,把它改进得更好。

    还有一些问题就不那么容易解决了,这几个问题在XRuby的blog上已经讨论过了,这里只是简单介绍一下。

    首先,还是性能。用C Ruby写的builtin在很多部分存在优化,这是Ruby写的代码无法做到的。比如Integer#times。如果用Ruby写大概会是这样:
    class Integer
        def times
            i = 0
            while i < self
                yield i
                i += 1
            end
            self
        end
    end

    看上去这个实现很简单,但无论是“<”,还是“+”,都需要调用方法实现,而我之前介绍过Ruby中的方法查找,显然,对于普通的Fixnum而言,它远不如直接在Java代码中些for循环来得快。

    再有,就是Ruby的类是开放的,如果一个方法中用到另一个方法,那么被调用的方法如果被修改的话,就会对调用端的方法产生影响。还是前面这个Integer#times,显然,如果修改了Fixnum的“<”或是“+”的实现,就会对times的实现产生影响,这会造成与C Ruby实现上的不兼容,因为其中对Fixnum进行了优化,不会受到Ruby层次上“<”、“+”实现的影响。当然,在XRuby的blog上,有人提出的了一些解决方案,但在我看来,这样的解决方案只是可以实现,却完全没有美感可言。

    用Ruby编写builtin不像初看起来那么差劲,却是需要小心翼翼。
    分享到:

    历史上的今天:

    告别mock 2011-05-23
    画地为牢 2010-05-23
    引用地址: