Why is this CoffeeScript faster than this Ruby script?
我正在解决一个问题,这个问题要求我找出4000000以下所有偶数的斐波那契数之和,我注意到下面的coffeeesccript比下面的ruby执行得更快。
咖啡描述1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | sum = 0 f = (n) -> if n == 0 then return 0 else if n == 1 then return 1 else return f(n-1) + f(n-2) console.log"Starting..." for i in [1..4000000] ff = f(i) break if ff >= 4000000 sum += ff if ff % 2 == 0 console.log".." + ff console.log"Sum:" + sum |
红宝石
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | sum = 0 def F(n) if n.eql? 0 return 0 elsif n.eql? 1 return 1 else return F(n-1) + F(n-2) end end puts"Starting..." 4000000.times do |num| the_num = F(num) break if the_num >= 4000000 sum += the_num if the_num % 2 == 0 puts".." + the_num.to_s end puts"Sum:" + sum.to_s |
号
Ruby脚本花费了近6-8秒的时间来查找4000000以下的所有偶数斐波那契数,而完成nodejs执行coffeescript所需的时间大约为0.2秒。这是为什么??
1 2 3 4 | $ ruby --version ruby 2.1.0p0 (2013-12-25 revision 44422) [x86_64-darwin12.0] $ node --version v0.10.25 |
让我们使用Ruby进行分析,教授:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | # so_21908065.rb sum = 0 def F(n) # using == instead of eql? speeds up from ~ 7s to ~ 2s if n == 0 return 0 elsif n == 1 return 1 else return F(n-1) + F(n-2) end end puts"Starting..." 1.upto(4000000) do |num| the_num = F(num) break if the_num >= 4000000 sum += the_num if the_num % 2 == 0 puts".." + the_num.to_s end puts"Sum:" + sum.to_s |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | $ ruby-prof so_21908065.rb %self total self wait child calls name 16.61 27.102 27.102 0.000 0.000 87403761 Fixnum#== 9.57 15.615 15.615 0.000 0.000 48315562 Fixnum#- 4.92 8.031 8.031 0.000 0.000 24157792 Fixnum#+ 0.00 0.000 0.000 0.000 0.000 70 IO#write 0.00 163.123 0.000 0.000 163.123 1 Integer#upto 0.00 163.122 0.000 0.000 163.122 48315596 *Object#F 0.00 0.000 0.000 0.000 0.000 35 IO#puts 0.00 0.000 0.000 0.000 0.000 34 Fixnum#to_s 0.00 0.001 0.000 0.000 0.000 35 Kernel#puts 0.00 0.000 0.000 0.000 0.000 34 String#+ 0.00 163.123 0.000 0.000 163.123 2 Global#[No method] 0.00 0.000 0.000 0.000 0.000 34 Fixnum#>= 0.00 0.000 0.000 0.000 0.000 2 IO#set_encoding 0.00 0.000 0.000 0.000 0.000 33 Fixnum#% 0.00 0.000 0.000 0.000 0.000 1 Module#method_added * indicates recursively called methods |
号
因此,主要的罪魁祸首是
正如@holgerjust所指出的,由于JIT优化,"预热的"JRuby执行可能更快。