我正在尝试处理大量数字:
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)
怎么可能?
答案 0 :(得分:5)
我说一个Enumerator是一个比记忆慢得多的中间人。
此前还有reported和Ruby核心团队成员Yusuke Endoh said:
枚举器::懒惰不是银弹;它消除了开销 创建一个中间数组,但带来了调用的缺点 一个街区。不幸的是,后者比前者大得多。 因此,一般来说,Lazy确实会带来性能上的缺陷。
我刚想到的一个类比:想象一下你为朋友建造一些家具。
非懒惰:你建造整件东西,租一辆卡车,然后开车送给你的朋友。
懒惰:你建造一个小块并用你的车把它带给你的朋友。你建造下一个小件并用你的车把它带给你的朋友。你建造下一个小件并用你的车把它带给你的朋友。等等。
是的,租用那辆卡车是额外的开销,但与你的车一遍又一遍地开车相比,这一点都没有。
懒惰可以节省时间的真正原因是,在你的朋友发现你和他的妻子睡觉后,你的朋友发现你已经不再是朋友,而且他不想要你的愚蠢家具。再也没有,你根本没有建造剩余的部分。