为什么红宝石中的"eval"如此之慢?

Zep*_*lee 2 ruby

在下面的红宝石代码中,'eval'比'def'慢10倍以上.

我理解'eval'需要解析字符串,但我想在这个例子中只需要完成一次.

require "benchmark"
GC.disable

eval "def run1; 10_000.times { #{"$a[5]\n" * 10_000} } end"
def run2
    10_000.times { "#{"$a[5]\n" * 10_000}" } 
end

$a = [1,2,3,4,5,6,7,8,9,10]

puts "run1:"
puts Benchmark.measure { run1 }

puts "run2:"
puts Benchmark.measure { run2 } 
Run Code Online (Sandbox Code Playgroud)

Nic*_*eys 7

你没有比较等效函数. run1最终成为一个$a[5]\n单个字符串中10,000次的函数,因为字符串插值在字符串构建之前发生,之后eval被调用. run2按照人们的预期运行.

为了看到差异,ruby-prof投入混合:

require "benchmark"
require 'ruby-prof'

GC.disable

eval "def run1; 10_000.times { #{"$a[5]\n" * 10_000} } end"
def run2
    10_000.times { "#{"$a[5]\n" * 10_000}" } 
end

$a = [1,2,3,4,5,6,7,8,9,10]

puts "run1:"
RubyProf.start
puts Benchmark.measure { run1 }
result = RubyProf.stop
printer = RubyProf::FlatPrinter.new(result)
printer.print(STDOUT)

puts "run2:"
RubyProf.start
puts Benchmark.measure { run2 }
result = RubyProf.stop
printer = RubyProf::FlatPrinter.new(result)
printer.print(STDOUT)
Run Code Online (Sandbox Code Playgroud)

编辑:这里是结果(我删除了Benchmark调用以将其修改为基础)

(nick@monster)-(~/Desktop)
(523)?? ruby derp.rb 
run1:
Thread ID: 2156059640
Fiber ID: 2163430960
Total: 484.962207
Sort by: self_time

 %self      total      self      wait     child     calls  name
100.00    484.962   484.962     0.000     0.000        1   Integer#times 
  0.00    484.962     0.000     0.000   484.962        1   Global#[No method] 
  0.00    484.962     0.000     0.000   484.962        1   Object#run1 

* indicates recursively called methods
run2:
Thread ID: 2156059640
Fiber ID: 2163430960
Total: 0.265188
Sort by: self_time

 %self      total      self      wait     child     calls  name
 94.02      0.249     0.249     0.000     0.000    10000   String#* 
  5.98      0.265     0.016     0.000     0.249        1   Integer#times 
  0.01      0.265     0.000     0.000     0.265        1   Global#[No method] 
  0.00      0.265     0.000     0.000     0.265        1   Object#run2 

* indicates recursively called methods
Run Code Online (Sandbox Code Playgroud)