代码之家  ›  专栏  ›  技术社区  ›  Idan Arye

Ruby的“懒惰”性能不如分配大量列表?

  •  5
  • Idan Arye  · 技术社区  · 7 年前

    我正在尝试处理一个大的数字列表:

    require 'benchmark'
    
    N = 999999
    
    Benchmark.bm 10 do |bm|
       bm.report 'Eager:' do
     (0..N).select(&:even?).map{|x| x * x}.reduce(&:+)
       end  
       bm.report 'Lazy:' do
     (0..N).lazy.select(&:even?).map{|x| x * x}.reduce(&:+)
       end  
     end;
    

    据我所知,懒惰版本应该快得多,因为急切版本需要分配两个列表,每个列表包含50万个项目(一个用于 select 一个用于 map )而懒惰的版本正在流式传输一切。

    然而,当我运行它时,懒惰版本需要的时间是渴望版本的两倍多!( http://rextester.com/OTEX7399 )

             user     system      total        real
    Eager:       0.210000   0.010000   0.220000 (  0.216572)
    Lazy:        0.580000   0.000000   0.580000 (  0.635091)
    

    怎么可能呢?

    1 回复  |  直到 7 年前
        1
  •  11
  •   Stefan Pochmann    7 年前

    我要说的是,计数员是一个比记忆慢得多的中间人。

    这也是 reported 不久前,Ruby核心团队成员 Yusuke Endoh said :

    枚举器::懒惰不是银弹;它消除了 创建中间数组,但会带来调用的缺点 一个街区。不幸的是,后者比前者大得多。 因此,一般来说,懒惰确实会带来性能缺陷。


    我刚刚想到了一个比喻:想象你正在为一个朋友做一些家具。

    • 不懒惰:你建造了整件东西,租了一辆卡车,然后把它开给你的朋友。

    • 懒惰:你造了一个小零件,用你的车把它送到你的朋友那里。你建造下一个小零件,然后用你的车把它送到你的朋友那里。你建造下一个小零件,然后用你的车把它送到你的朋友那里。等等

    是的,租那辆卡车是额外的开销,但这与你开车一次又一次相比算不了什么。

    懒惰可以节省时间的真正原因是,在前几件之后,你的朋友发现你和他的妻子睡了,所以现在你不再是朋友,他不再想要你的愚蠢家具,你也不再建造剩下的家具。