为什么我的宝石需要这么长时间才能加载?

cge*_*nco 14 ruby rubygems

我正在开发我的第一个名为t_time_tracker的宝石(哇哦!).一切都在发展中很好; 我尽可能地尽量减少执行时间,尽可能减少执行时间:

t_time_tracker[master*]% time ruby -Ilib ./bin/t_time_tracker 
You're not working on anything
0.07s user 0.03s system 67% cpu 0.141 total
Run Code Online (Sandbox Code Playgroud)

(这是我的应用程序的"hello world" - 没有参数调用它只打印出"你没有做任何事情")

大约十分之一秒,使用我的CPU的67% - 很酷,我可以忍受.感觉相当瞬间.让我们构建它:

$ gem build t_time_tracker.gemspec
$ gem install ./t_time_tracker-0.0.0.gem
Run Code Online (Sandbox Code Playgroud)

并使用已安装的二进制文件执行完全相同的操作:

$ time t_time_tracker
You're not working on anything
t_time_tracker  0.42s user 0.06s system 93% cpu 0.513 total
Run Code Online (Sandbox Code Playgroud)

半秒钟?!那个是从哪里来的?!让我们添加一些调试输出,并从开发二进制文件中包含系统gem,以查看瓶颈所在:

t_time_tracker[master*]% time ruby ./bin/t_time_tracker  
(starting binary)
(require 'time' and 'optparse')
0.041432
(before `require 't_time_tracker')
0.497135
(after `require 't_time_tracker')
(Gem.loaded_specs.keys = t_time_tracker)
(initializing TTimeTracker class)
You're not working on anything
ruby ./bin/t_time_tracker  0.44s user 0.07s system 91% cpu 0.551 total
Run Code Online (Sandbox Code Playgroud)

好吧,所以`require't_time_tracker'线似乎是罪魁祸首.让我们再次尝试将其缩小范围:

$ irb
>> t=Time.now; require 't_time_tracker'; puts Time.now-t
0.046792
=> nil
Run Code Online (Sandbox Code Playgroud)

...什么?但这只需要半秒钟!让我们尝试用我们的调试输出构建gem:

$ gem build t_time_tracker.gemspec
$ gem install ./t_time_tracker-0.0.0.gem
$ time t_time_tracker
(starting binary) <---noticeable half second delay before this line shows up
(require 'time' and 'optparse')
0.050458
(before `require 't_time_tracker')
0.073789
(after `require 't_time_tracker')
(Gem.loaded_specs.keys = t_time_tracker)
(initializing TTimeTracker class)
You're not working on anything
t_time_tracker  0.42s user 0.06s system 88% cpu 0.546 total
Run Code Online (Sandbox Code Playgroud)

所以,这0.5秒延迟来自哪里?我通常不在乎,但这是我每天要打五十次来更新我正在做的事情.50*0.5秒*365天*70年=失去15天的生命.

系统信息:

Mac OS X 10.7.3.2 GHz Intel Core 2 Duo.4 GB内存.红宝石1.9.2p290.

% gem -v
1.8.10<---noticeable half second delay before this line shows up
% gem list | wc -l
209
Run Code Online (Sandbox Code Playgroud)

Sim*_*ang 2

自从我看到这个以来已经有一段时间了,但 RubyGems 在过去(也许现在)需要很长时间才能加载,主要有两个原因:

  • 它将通过“yaml”加载许多相对昂贵的库,例如“time”。通常你并不关心,因为它相对于 ruby​​ 本身来说很慢,但与许多脚本的运行时间相比并不慢。
  • 它会扫描所有已安装的 gem,并将最新的 gemspec 加载到内存中。如果你有很多宝石,这需要很长时间。

这些问题可能仍然存在,也可能不再存在。然而,RubyGems 总会带来一些开销如果您确实需要性能,那么只需自己设置加载路径即可!如您所知,没有 RubyGems 的 Ruby 速度非常快。

要查看 gem 的安装位置:

gem list -d YOUR_GEM_NAME
Run Code Online (Sandbox Code Playgroud)

您将看到安装目录。您的 gem 将位于 INSTALL_DIR/gems/GEM_NAME-VERSION,因此请尝试执行:

time ruby -IINSTALL_DIR/gems/GEM_NAME-VERSION/lib INSTALL_DIR/gems/GEM_NAME-VERSION/bin/t_time_tracker
Run Code Online (Sandbox Code Playgroud)

这是很多,但您应该能够将其包装在一个单独的脚本中,如下所示(将其命名为 t_time_tracker):

#!/usr/bin/env ruby -IINSTALL_DIR/gems/GEM_NAME-VERSION/lib
load 'INSTALL_DIR/gems/GEM_NAME-VERSION/bin/t_time_tracker'
Run Code Online (Sandbox Code Playgroud)

然后:

chmod +x t_time_tracker
time ./t_time_tracker
Run Code Online (Sandbox Code Playgroud)

并将该文件放在路径中的任何位置。RubyGems 会自动为您完成,但您当然也接受 RubyGems 的开销。