论坛首页 编程语言技术论坛

骂一骂Ruby

浏览 23815 次
锁定老帖子 主题:骂一骂Ruby
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2006-08-25  
charon 写道
buaawhl 写道

Python, ErLang都有VM,都有编译步骤。right?
这样,Python, ErLang都可以脱离源码,直接用中间代码部署运行。right?
Python是否动态强类型?Python的编译步骤是否进行类型检查?

python可以直接用中间代码执行,而且中间代码有多种类型
python是动态强类型的。但是编译期肯定不做类型检查,连变量名都不检查
这个是动态语言的短板。就是说必须把单元测试做到弱条件组合覆盖才行(比语句覆盖要强多了),才可能杜绝语法错误
比如
...
if((a>b or c>d); and f>g);:
    print 'aaa'
else:
    print 'bbb'
...

这种情形下,在编译的时候并不检查a,b,c,d,e,f的存在性,更不用说类型了。而且如果a>b,则c/d的存在与否都无关紧要(因为被短路了).
这样,在单元测试的时候必须要有执行到c>d的case,否则如果里面有语法错误,那就歇菜了
而要做到语句覆盖,只要a>b,f>g,和a>b,f<g两个情况就可以了


thanks for the clarification.

Python编译的中间码都是些啥?
估计是很高级的形式,里面包括了大量的 "(a>b or c>d) and f>g"这些字符串。
0 请登录后投票
   发表时间:2006-08-25  
解释器的形式有两种,一种是直接遍历AST进行计算,另外一种方式是编译成VM的指令,然后由VM解释执行。VM有两种方式,一种是Stack Machine,另外一种是register machine.
理论上的研究一直说register machine效率比较高,但实现比较困难。因此绝大多数主流VM都是Stack模型,perl6的parrot VM是少见的register模型。Ruby也可以跑在parrot上(Cardinal)。

当然编译器和VM可以进行比较高级的优化,例如direct threaded code(及其变种、增强),Stack Caching,super instruction, tail optimization, last call  optimization等等,还可以进行JIT。也有编译器直接在中间码中加入native code的做法,譬如erlang的HiPE就可以做到。比较特殊的语言,例如erlang还可以在虚拟机内部实现完全不同操作系统的进程调度。这些在直接遍历AST的方法不可能做到。

但是Ruby目前有很多的虚拟机移植。包括n个ruby-&gt;CLR VM,ruby-&gt;jvm,ruby -&gt;parrot,以及原生的YARV,所以这个问题不会太大。关键是有人用,就有人搞。

但是遍历AST的方法 ,GC是没有问题,Ruby的GC是标准的Mark&Sweep,还没有做到分代。并且需要在mark的时候直接在对象的头上flags里面标记,可能会引起不好的cache因为,因此变成Bitmap形式也许更加好一点。试验中......
0 请登录后投票
   发表时间:2006-08-25  
potian 写道
解释器的形式有两种,一种是直接遍历AST进行计算,另外一种方式是编译成VM的指令,然后由VM解释执行。VM有两种方式,一种是Stack Machine,另外一种是register machine.
理论上的研究一直说register machine效率比较高,但实现比较困难。因此绝大多数主流VM都是Stack模型,perl6的parrot VM是少见的register模型。Ruby也可以跑在parrot上(Cardinal)。

当然编译器和VM可以进行比较高级的优化,例如direct threaded code(及其变种、增强),Stack Caching,super instruction, tail optimization, last call  optimization等等,还可以进行JIT。也有编译器直接在中间码中加入native code的做法,譬如erlang的HiPE就可以做到。比较特殊的语言,例如erlang还可以在虚拟机内部实现完全不同操作系统的进程调度。这些在直接遍历AST的方法不可能做到。

但是Ruby目前有很多的虚拟机移植。包括n个ruby-&gt;CLR VM,ruby-&gt;jvm,ruby -&gt;parrot,以及原生的YARV,所以这个问题不会太大。关键是有人用,就有人搞。

但是遍历AST的方法 ,GC是没有问题,Ruby的GC是标准的Mark&Sweep,还没有做到分代。并且需要在mark的时候直接在对象的头上flags里面标记,可能会引起不好的cache因为,因此变成Bitmap形式也许更加好一点。试验中......




虽然不能完全看懂,但是受益不少。
0 请登录后投票
   发表时间:2006-08-26  
charon 写道
虽然看到很多,但是还是不能理解symbol的目的。
怎么看都象一个指针,但是为什么要出现?
http://www.rubycentral.com/faq/rubyfaq-6.html#ss6.1

symbol确实对新接触ruby的人看上去比较古怪。习惯了就好,只是个name罢了。ruby的string每个都是单独对象(哪怕内容一样),内存利用上不经济。
buaawhl 写道

Python编译的中间码都是些啥?
估计是很高级的形式,里面包括了大量的 "(a&gt;b or c&gt;d) and f&gt;g"这些字符串。

Python Byte Code Instructions
0 请登录后投票
   发表时间:2006-08-26  
cookoo 写道
charon 写道
虽然看到很多,但是还是不能理解symbol的目的。
怎么看都象一个指针,但是为什么要出现?
http://www.rubycentral.com/faq/rubyfaq-6.html#ss6.1

symbol确实对新接触ruby的人看上去比较古怪。习惯了就好,只是个name罢了。ruby的string每个都是单独对象(哪怕内容一样),内存利用上不经济。


如果内容一样,C字符串char * 是共享的,

Struct RString是字符串类String和子类的实例的结构。
 330 struct RString {
 331     struct RBasic basic;
 332     long len;
 333     char *ptr;
 334     union {
 335         long capa;
 336         VALUE shared;
 337     } aux;
 338 };
 339 
(ruby.h);



aux.shared利用已有的字符串文本加快字符串对象的创建,当然也可以节约大量的内存空间,如果一样的话。我们可以看看下面这段Ruby代码:
while true do  
  str = "head"       
  str.concat("tail");      
end

这是一个无穷的循环。每一次都需要创建一个单独的字符串对象,它的内容是”head”,然后加上”tail”,变成”headtail“,而每个字符串对象都持有一个不同的char[]。 如果不共享的话就会有无数份拷贝,但字符串内容实际上却没有发生任何改变。

aux.shared可以使用同一字符串文本的字符串对象共享同一份char[]。如果其中某一个共享的字符串要发生变化,那么字符串首先复制到一个块不共享的内存,然后对这个新的copy进行改变。这是标准的”copy-on-write”做法。在使用一份共享的char[]时,对象结构的basic.flags中的标志ELTS_SHARED位被置上,而aux.shared就指向那个原始的对象。
0 请登录后投票
   发表时间:2006-08-26  
potian你说的有道理,受教了。我另外做了如下试验:
a = []
(1..10**5);.each {|x| a << 'hello'}

内存涨了大约3M
b = []
(1..10**5);.each {|x| b << 'hello'.concat(x.to_s);}

区别只是b中每个串都不同,这回内存涨了大约9M。
而通过
c = ''
(1..10**5);.each {|x| c << x.to_s}

说明这么多不同部分一共也就增加1M不到,内存节约还是明显的。
0 请登录后投票
   发表时间:2006-08-26  
引用

ruby的string每个都是单独对象(哪怕内容一样),内存利用上不经济


觉得cookoo中的了
0 请登录后投票
   发表时间:2006-08-28  
liuyifan.com 写道

觉得cookoo中的了

什么意思?看不懂这中文啊
0 请登录后投票
   发表时间:2006-08-28  
cookoo 写道
liuyifan.com 写道

觉得cookoo中的了

什么意思?看不懂这中文啊


符号扯了这么多,还是你一句中的的说。。。
0 请登录后投票
   发表时间:2006-08-29  
cookoo 写道
potian你说的有道理,受教了。我另外做了如下试验:
a = []
(1..10**5);.each {|x| a << 'hello'}

内存涨了大约3M
b = []
(1..10**5);.each {|x| b << 'hello'.concat(x.to_s);}

区别只是b中每个串都不同,这回内存涨了大约9M。
而通过
c = ''
(1..10**5);.each {|x| c << x.to_s}

说明这么多不同部分一共也就增加1M不到,内存节约还是明显的。


irb(main);:001:0> a = b = 'hello'
=> "hello"
irb(main);:002:0> a.object_id
=> -606923358
irb(main);:003:0> b.object_id
=> -606923358
irb(main);:004:0> c = 'hello'
=> "hello"
irb(main);:005:0> c.object_id
=> -606933008


如果先把'hello'保存在一个变量里,再加到到Array里面,应该和Symbol效果相近了吧。
0 请登录后投票
论坛首页 编程语言技术版

跳转论坛:
Global site tag (gtag.js) - Google Analytics