今年是 Ruby 20 年(http://www.infoq.com/cn/articles/Thriving-Ruby-language-Family),我们想就此机会跟 infoQ 社区的朋友一起对 Matz 做一个采访,如果采访人是你,你最想问 Matz 的问题是什么?
我想知道,他和 PHP 5.5 以及即将到来的 PHP6 相比较有什么优势和不足。php 也有很多优秀的框架,例如 YII,Laravel,Fuelphp,Zend Framework cake 等等
他们有好多是借鉴了 ROR 的特性和快速开发的理念。由于 php 本身的限制,面向对象的方式有点不同。
刚刚接触 ruby 一天时间,我也问不出什么好问题。深入的问题。
就想知道,web 开发,只讲究快速快发,不断改进。用 yii 还是 rails 比较合适。
(个人觉得语法什么的并不是重要的,最重要的是开发速度,组件,开源项目,开源社区的质量 )
目测,驾驭 ruby 比 php 要难度大一点,招人是不是不是很好招?
现在在广州我们很容易就可以找到一个 php 新手,带一个月基本上就可以拿框架用了。ruby 门槛貌似稍微高一点。
本人不是专业的技术队伍,只是昨天研究了一下 ruby, 结合了一下自学 php 的经历。不要喷我 , 多谢。
@lgn21st 啊,期待,什么时候进行采访呀?
嗯,先就想到这些。:)
Javascript 这门语言有很多问题,所以有一本书叫做《Javascript 语言精粹》,Ruby 是否有同样的情形?因为做一件事情,Ruby 往往有很多种方式,有没有一个让大众认可的 ruby best practice?
关于 CRuby
关于 MRuby
上面的一些问题在网络上都可以搜索到一些资料,之所以列出来,是想让 Matz 亲自谈一谈啦。
我想问 大师对于 Ruby 不同版本的语法变化比较大(甚至不兼容)这方面在后期有什么样的计划~,后期会不会稳定下来,例如 ruby1.8 和 1.9 python2.7 和 3.0。刚开始接触 ruby,别的谈不上来~但是感觉 ruby 和 python 就在版本兼容性上真的很令人抓狂~
我的问题:
给两个建议:
jit 编译就是用空间换时间... 解释器的优势是操作的抽象度高,可执行代码可以挤到很小的内存中去,mruby 用 jit 的话也就只能适用于很小的一部分移动设备...
另外解释器也能到达很高的速度的,luajit2 的解释模式就比 luajit1 的 jit 模式快。1.8 时代有个 AOT (ahead of time) 编译器 ruby2cext, 把 ruby 翻译成 C, 然后让 C 编译器用最大优化度去编译,可以提升不少速度,但是这个方法对 1.9 已经没有改进的效果了... 一个 jit 的优化能力一般是比不上 C 编译器的...
完成日常任务如 rake 或者爬虫的话,解释模式执行基本都是比 jit 快,因为很多代码都是只跑一遍,先编译成机器码再跑反而慢了。jit 对多次调用的一些 "热" 方法效果明显,但是 ruby 中比较 "热" 的很多方法已经是 C 实现的了。如果采用 jit, 可能需要把很多实现改回 ruby 才能保证速度 (就像 rubinius 里把很多很多核心方法都用 ruby 重新实现了一遍...). 有些代码多而且"热度均匀"的 java 应用为了尽可能多的 jit, 把 permanent generation 调得非常大 (好几 G 之类的), 提升效果也不明显,因为可执行机器码多了 page miss 的情况也会很严重...
内存也是考虑因素之一。jit 后消耗内存明显增多,现在 ruby 的字节码是按照平台长度对齐的,其实是 "qword code", 吃内存已经不小了... 如果采用 jit, 可能要重新设计字节码,使用更节省内存的表示方式?但是节省内存的字节码表示方式往往不能对齐,不能对齐就会影响解释执行的速度,并且使一些技巧如 inline method caching 更难实现...
大量运用了元编程和反射的代码,运行的时候 jit 也要多次重新编译...
有了 jit 之后还需要做很多工作去优化,例如 java 的 jit 就能扫描一些短的方法并且把它 inline 过来,减少 method call 的时间损耗。但是一些优化手段随着 CPU 的发展没有效果甚至是反效果了,像分支预测能力比较强的 CPU, 一些方法调用的损耗几乎可以忽略,inline 进来反而增加了代码的大小,没达到提速的效果... 所以现在的最新的编译器 gcc 和 vc 都是用 profile based 的手段去检测一些指令或者代码的代价,然后按照代价选择生成最佳的机器代码。但是一个 jit 要做到这种程度代价也很高的...
http://nominolo.blogspot.jp/2012/07/implementing-fast-interpreters.html
虽然实现一个有效果的 jit 很困难,但 ruby 和 mruby 的 x86 jit 也是有人在做的
再另外,速度优化不是一个 jit 能搞定的事情,gc, method dispatch 都还有优化的空间,而且现在解释器也还没有达到最优化:ruby 2.0 stack caching 的优化开关还没打开 (有些测试还跑不过去,而且没有完全的速度提升), context threading, super instruction, manual branch prediction 之类的优化技巧也还没应用上。我觉得 ruby 离 jit 还是挺远的路要走的,或者解释器上有进一步突破,干脆就不需要 jit 了,又或者发展出一个混合解释和 jit 执行的模式 (inline instruction) 也说不定...
是的,JIT 无法回避的问题就是生成代码需要时间,生成出来的代码还要占空间导致更多 cache miss,很容易就得不偿失的。而且总觉得又多了个安全隐患...
一个 jit 的优化能力一般是比不上 C 编译器的
不是那么绝对的,JIT 能知道运行期信息,有时候是能生成非常紧凑的代码,当然代价是要插入很多 guard,检查是否符合你之前编译的时候假设的情况。不符合就 fallback 到解释模式。假如 fallback 到 method JIT 的话,那就更耗内存了,引起 cache miss 就啥都没有了... Mozilla 好像在搞的那个是能共用部分 tracing JIT 和 method JIT 的生成代码的???
如果采用 jit, 可能要重新设计字节码,使用更节省内存的表示方式?
为啥?一般解释型语言的字节码都是很贴近语言本身的,也就是说很紧凑的。你可以把编译/JIT 过程看作内联解释器再把常量代入,消除冗余代码,显然很容易生成比解释器字节码长得多的代码。解释器字节码那里省下来的其实也不多
大量运用了元编程和反射的代码,运行的时候 jit 也要多次重新编译...
没看出来能比别的情况多 ...
分支预测能力比较强的 CPU
我一直没搞明白 (当然也没尝试去搞明白) 分支预测的命中率是怎么能达到 90% 以上的。
发展出一个混合解释和 jit 执行的模式 (inline instruction) 也说不定...
tracing JIT 被你赤裸裸地无视了
#51 楼 @bhuztez offline 编译器不用考虑编译时间,可以做复杂很高的代价比较,找到最佳的生成结果。vm 对 offline 编译器的唯一优势是按照运行情况去动态修改代码,但现在的 C 编译器各种黑魔法,已经具备一些运行时修改代码的能力了... 例如用 C++ 实现 singleton, getInstance()
这么写的话:
class Klass {
static Klass* instance = NULL;
public:
static Klass* getInstance() {
if (!instance) {
instance = new Klass();
}
return instance;
}
...
}
其中的 if
条件判断在多次运行之后可以被省略掉,不判断就直接返回 instance
了。
ruby vm 已经有常量代入的能力了,和 jit 无关,叫做 inline const cache
. 实现方法是第一次调用这个常量的时候就在 byte code 中嵌入常量的值。如果发生了常量重新定义,vm 里维持的一个版本字段会更新,然后所有的 const cache 都会失效。
把 bytecode 指令的实现作为模板写出来的 jit 几乎没有速度改进的... 这样的 jit 比 direct threading 只少了 goto *ip++;
产生的几条指令,但是用了 operand predecode 手段的话,可以利用 CPU 的乱序执行能力在很少的时钟周期内完成执行完很多指令。真正有效果的 jit 要么需要手写很多汇编代码,要么重新做寄存器分配,没有 super instruction 那么好实现,而且 super instruction 可以利用 offline 编译器的优化能力,可移植性也更好...
分支预测有很多种,最简单的是预测 goto label
. 某些 CPU 可以还能根据段寄存器或者指令寄存器 RIP
指向的地址去扫描代码找跳转,所以有 context threading 的优化方法:某些情况下把 vm 里虚拟的 instruction pointer 放到指令寄存器中去。至于 "90% 的分支预测命中率" 之类的看不到上下文没什么意义吧...
做 jit 有很多方法... rubinius 是基于 llvm bytecode 做 jit 的,但由于多了一个 llvm 字节码中间层,编译的消耗也多大,ytljit 是基于 yarv bytecode 的 jit. 我觉得 tracing jit 更适合 v8 那种一开始就放弃 bytecode 的 vm ...
已经具备一些运行时修改代码的能力了
不是的。你在运行期改不了代码段里的东西的,那个内存页是可执行且只读的...你改了就执行不了了。假如你要写到新的内存页里面,那就和 JIT 一样变安全隐患了
ruby vm 已经有常量代入的能力了
我说的不是这个...我说的是最普通的情形,就比如x+y
,解释器就只能这么运行了。而编译器或者 JIT,知道x
和y
的值,就可以直接把x
和y
当作常量代入,于是这个表达式就被优化掉了。
把 bytecode 指令的实现作为模板写出来的 jit 几乎没有速度改进的
这还导致了更多 cache miss 呢...只是需要有效果,像 PyPy 那样也可以了。在运行期编译解释器代码就可以了...但是 Python 实在不是一门适合用来写编译器的语言...
http://tratt.net/laurie/tech_articles/articles/fast_enough_vms_in_fast_enough_time
我觉得 tracing jit 更适合 v8 那种一开始就放弃 bytecode 的 vm ...
V8 倒是一开始是 method JIT 后来才 tracing JIT 的,而 Mozilla 家的各种 monkey 倒是一上来就是 tracing JIT...
对于 Python 的 decorator 有什么看法—— Ruby 今后会增加 decorator 吗?
突然想起来,特来挖坟
从语法上讲实现这个功能毫无压力。但是从语义上讲,Ruby 有函数这个概念吗,有吗?没有吗?反正怎么说都说不清楚,哈哈哈哈哈哈哈......