Ruby range 展开为何比 while 慢很多

lilijreey · 2018年10月16日 · 最后由 a-wing 回复于 2018年10月17日 · 556 次阅读
def rran()
  s = 0
  (0..10000000).each do |i|
    s += i
  end
end

def tfor()
  n=0
  s=0
  while (n+=1) < 10000000
    s+=n
  end

end
[148] pry(main)> Benchmark.measure { tfor()}
=> #<Benchmark::Tms:0x000000029cf458
 @cstime=0.0,
 @cutime=0.0,
 @label="",
 @real=0.22141856199596077,
 @stime=0.0,
 @total=0.21999999999999997,
 @utime=0.21999999999999997>
[149] pry(main)> Benchmark.measure { rran()}                                                              
=> #<Benchmark::Tms:0x00000002969388
 @cstime=0.0,
 @cutime=0.0,
 @label="",
 @real=0.3831686199409887,
 @stime=0.0,
 @total=0.3700000000000001,
 @utime=0.3700000000000001>

如图 for 版本的循环比range版本的快很多。 按道理应该是一样快才对啊。 请大牛解释一下

共收到 6 条回复

应该是 each 需要调用 block 的消耗吧,建议用更牛逼的 profile 工具试试能不能看?

如果这样ruby的优化还是很差劲的。

《Ruby原理剖析》里面介绍过,each 方法每次迭代都准备一大波对象,执行很多逻辑。而while只需要调整PC指针的值,性能不在一个量级。 具体的细节我得回去翻翻书了。

early 回复

好吧,那这样有回到while/ for 的老路了。 感觉echo 调用block可以内联编译。 难道ruby的解释器没有优化功能吗。

你去读完 Ruby原理剖析 再回来问问题吧(((

lilijreey 回复

each 方法 其实和其他方法的实现不一样。。。。印象中 each 应该更快。((

我只是猜测。while 执行更快可能仅限于一些简单数值

while/ for 在遍历比较大的对象好像有其他问题(

需要 登录 后方可回复, 如果你还没有账号请点击这里 注册