经常有这样的代码
array.sort_by(&:date).take 3
现在可以这么写:
array.min_by 3, &:date
其实现不需要全排序和额外分配一个中间数组,速度往往更快
new way 但是方法实现中,1.9 和 2.2,是一样的
2.2
static VALUE
enum_min_by(VALUE obj)
{
VALUE memo[2];
RETURN_ENUMERATOR(obj, 0, 0);
memo[0] = Qundef;
memo[1] = Qnil;
rb_block_call(obj, id_each, 0, 0, min_by_i, (VALUE)memo);
return memo[1];
}
a = [1, 2, 3, 4, 3, 2, 1, 0, -9, 387]
a.min_by 3, &:to_i
#=> [-9, 0, 1]
1.9
static VALUE
enum_min_by(VALUE obj)
{
VALUE memo[2];
RETURN_ENUMERATOR(obj, 0, 0);
memo[0] = Qundef;
memo[1] = Qnil;
rb_block_call(obj, id_each, 0, 0, min_by_i, (VALUE)memo);
return memo[1];
}
a = [1, 2, 3, 4, 3, 2, 1, 0, -9, 387]
a.min_by 3, &:to_i
ArgumentError: wrong number of arguments(1 for 0)
from (pry):3:in `min_by'
#3 楼 @bhuztez 呃,register based VM 字节码占内存多。如果像 MRuby 那样用压缩的字节码跑 register based VM, 那执行每个指令都要经历一个 decode 过程,会产生不少消耗。现在完全用 C 实现的 Ruby VM 是很难像 Lua 那样利用乱序执行特性达到比较高执行效率的。
register based VM 的 register 是虚拟寄存器,在物理寄存器分配上也不一定有优势... stack based VM 也有很多利用物理寄存器技巧,例如把 stack 顶部 (经常 push pop 的内容) spill 到物理寄存器上,Ruby 源代码里改编译参数也能 enable 这个优化,只是实测没什么速度变化...
目前纯解释执行比较快的 PHP 和 Erlang 都是 register based。register based VM 虽然单条指令长了,但是指令数量少了,最终大小差不多的。
Lua 那样利用乱序执行
Lua 为啥要乱序执行?
register based VM 的 register 是虚拟寄存器,在物理寄存器分配上也不一定有优势...
x86 根本就没啥寄存器可以分配。register-based 也没必要非得分配在物理寄存器上。
#5 楼 @bhuztez -_- zend 运行时就是个呵呵吧... register 机在函数调用上还是得和 stack 机一样压栈,所以很多地方区别也没这么大。register 机字节码必然比 stack 机占空间多是公认的经验,因为很多连续运算的"中间数", 就是和栈高度吻合的,其中的 push/pop 指令会少很多,然后字节码占空间就大幅减小了。register 机设计得比较好可以只多 25% 左右,如果你有设计巧妙的 register 机指令集使得字节码可以小到和栈机差不多,求共享。
利用 OOO 是 LuaJIT 的解释器的汇编实现里有考虑减少指令之间的 bubble 的考虑 (还有先 decode 下条指令再 jump 也是这个目的)
#12 楼 @bhuztez 现在几乎都不用 32 位机器了,看 64 位的结果啊 http://benchmarksgame.alioth.debian.org/u64/compare.php?lang=yarv&lang2=php 而且那个 pidigits 的 Ruby 实现本来就有很大问题。而且类似这些 benchmark 的循环套循环代码在做网站中不还都是用 C 库搞的...