在函数而不是 class 中加载包的影响

Repercussion of loading packages within a function instead of class

假设我想使用一个名为 'toad' 的库。

我可以做到(在Ruby伪代码中):

require 'toad'

Class MyClass
 def do_stuff
   Toad.do_toad_stuff
 end
...
end

不过我也可以

...
 def do_stuff
   require 'toad'
   Toad.do_toad_stuff
 end
...

假设 toad 是一个相当小的图书馆。我在哪里做(真的)重要吗?如果重要的话,假设每次用户访问我的 Web 应用程序都会调用此函数几次。

我想我最终很好奇是否会发生任何优化。

这就是 do_stuff 被调用频率的问题。如果只是几次,则使用里面的require,否则只需要一次

很容易测试:

require 'benchmark'
require 'json' # require any library, doesn't matter

n = 1_000_000

def foo_with_require
  require 'json'
  2 + 2
end

def foo_without_require
  2 + 2
end

Benchmark.bm(20) do |benchmark|
  benchmark.report('require each time', 20) do
    n.times { foo_with_require }
  end
  benchmark.report('require once') do
    n.times { foo_without_require }
  end
end

结果如下:

                           user     system      total        real
require each time      2.260000   0.010000   2.270000 (  2.273471)
require once           0.080000   0.010000   0.090000 (  0.079403)

所以当函数体像 2 + 2 一样简单时,只需要一次大约快 30 倍,但是如果你的函数做任何更有意义的事情,差异将可以忽略不计。

几点:

  1. require 'toad' 放入方法中并不会改变它将常量(例如模块)和全局变量加载到 运行 程序的(全局)范围内的事实。
  2. require 会记住它已经加载的文件(参见 $LOADED_FEATURES)并且只会加载唯一的文件路径一次。
  3. 要推迟对文件的要求,直到有必要这样做,您可以使用 autoload(由于线程安全,它曾一度被弃用,但已经解决并且它仍然是内核的一部分),如下所示:

    class MyClass
      autoload :Toad, 'toad'
      ...
    end