为什么这个CoffeeScript比这个Ruby脚本更快?

时间:2014-02-20 12:38:32

标签: ruby node.js coffeescript

我正在解决一个问题,要求我找到所有偶数斐波那契数字在4,000,000以下的总和,我注意到下面的CoffeeScript执行速度比下面的Ruby快。

的CoffeeScript

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

红宝石

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秒来查找所有甚至斐波纳契数字都在4,000,000以下,而大约 0.2秒完成NodeJS执行咖啡因的翻译。这是为什么?

$ ruby --version
  ruby 2.1.0p0 (2013-12-25 revision 44422) [x86_64-darwin12.0]
$ node --version
  v0.10.25

1 个答案:

答案 0 :(得分:4)

让我们使用ruby-prof

对其进行分析
# 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

$ 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

所以主要罪魁祸首是Fixnum#==Fixnum#-Fixnum#+

正如@HolgerJust所指出的那样,由于JIT优化,可能会使一个“温暖”的JRuby执行速度更快。