由于GEM_HOME的要求,启动Ruby应用程序非常慢

Nie*_*een 6 ruby

我目前正在研究一个ruby应用程序,但它运行得非常(非常!)慢..直到现在,我已经尝试了一些事情,我可以将其缩小到主要问题:Ruby正试图寻找它的需要在$ LOAD_PATH中的每个目录中.

基本上我正在观察的是,ruby正在查看大量文件,试图查看是否需要存在.如果它找不到它们,它将进入下一个目录.好消息是我可以看到这种情况发生在strace上.有很多这样的输出:

open("/boa_proj_build/nsteen/.gem/gems/i18n-0.7.0/lib/commander/help_formatters/base.rb", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
open("/boa_proj_build/nsteen/.gem/gems/thread_safe-0.3.5/lib/commander/help_formatters/base.rb", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
open("/boa_proj_build/nsteen/.gem/gems/tzinfo-1.2.2/lib/commander/help_formatters/base.rb", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
open("/boa_proj_build/nsteen/.gem/gems/minitest-5.8.2/lib/commander/help_formatters/base.rb", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
open("/boa_proj_build/nsteen/.gem/gems/activesupport-4.2.4/lib/commander/help_formatters/base.rb", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
open("/boa_proj_build/nsteen/.gem/gems/climate_control-0.0.3/lib/commander/help_formatters/base.rb", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
open("/boa_proj_build/nsteen/.gem/gems/cocaine-0.5.7/lib/commander/help_formatters/base.rb", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
open("/boa_proj_build/nsteen/.gem/gems/boa_loggable-0.2.2/lib/commander/help_formatters/base.rb", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
open("/boa_proj_build/nsteen/.gem/gems/ruby_expect-1.6.0/lib/commander/help_formatters/base.rb", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
open("/boa_proj_build/nsteen/.gem/gems/cctools-3.0.1/lib/commander/help_formatters/base.rb", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
open("/boa_proj_build/nsteen/.gem/gems/git-1.2.9.1/lib/commander/help_formatters/base.rb", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
open("/boa_proj_build/nsteen/.gem/gems/naught-1.1.0/lib/commander/help_formatters/base.rb", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
open("/boa_proj_build/nsteen/.gem/gems/symbolizer-0.0.1/lib/commander/help_formatters/base.rb", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
open("/boa_proj_build/nsteen/.gem/gems/settingslogic-2.0.9/lib/commander/help_formatters/base.rb", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
open("/boa_proj_build/nsteen/.gem/gems/memoist-0.12.0/lib/commander/help_formatters/base.rb", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
open("/boa_proj_build/nsteen/.gem/gems/highline-1.7.8/lib/commander/help_formatters/base.rb", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
open("/boa_proj_build/nsteen/.gem/gems/commander-4.3.5/lib/commander/help_formatters/base.rb", O_RDONLY|O_CLOEXEC) = 8
Run Code Online (Sandbox Code Playgroud)

正如您所看到的,它正在浏览一些目录以找到它的要求.

使用测试应用程序对此进行跟踪,过滤ENOENT错误并计算出现次数,将显示以下有关输出的信息:

vdi9442:/boa_proj_build/nsteen/$ strace packager --version 2>&1 | grep ENOENT | wc -l
3454261
Run Code Online (Sandbox Code Playgroud)

当然,350万是很多.这将导致大约5分钟的加载时间(大约一半没有strace),然后输出它的版本号(命令gem的默认功能).

我已经删除了我的整个gem主目录,并再次运行测试,它立即更快,但我可以看到它再次查看那些少数宝石(像commander这样的依赖项),但是'只是'几千次出现而不是3.5密耳.

我的宝石env看起来像这样:

  - GEM PATHS:
     - /boa_proj_build/nsteen/.gem
     - /home/nsteen/.gem/ruby/2.1.0
     - /cadappl/ruby/2.1.1/ruby/lib/ruby/gems/2.1.0
Run Code Online (Sandbox Code Playgroud)

看起来ruby正在遍历我的整个加载路径,以满足一些依赖关系.这很好,但这只是变得越来越糟糕.有人知道发生了什么事吗?我怀疑这不是想要的/默认行为吗?

有人知道发生了什么事吗?我怎么能加快速度呢?

Bas*_*man 4

有很多方法可以处理这个问题,包括我不会涉及的 gemrc 文件。我将提到一些您可以选择的选项:

解决方案一:

另一个答案是正确的,但我想对这个主题进行一些扩展,因为这是人们似乎经常面对的问题。RVM 可以提供帮助。为此,我们设计了一个特殊功能:宝石镶嵌。我个人已经转向 rbenv 并且没有回头。Rbenv 对您的环境的干扰比 RVM 少得多,但它们都很棒。您可以在 RVM 和 rbenv 中使用 gemset,以限制您的应用程序可以使用哪些 gem。您也可以制作特定于应用程序的宝石集。使用 gemset,您的应用程序将在一个位置查找,并且仅加载已使用的 gem。它不会与其他应用程序宝石集混合。它最好的事情是自动的,您只需要设置一次,当您位于该目录中时它就会自动切换。它还与 Rubymine 和其他支持 Ruby 的 IDE/编辑器集成。

解决方案2:

将环境变量设置GEM_PATH为位置之一。这会覆盖其他一切,因此它至少会停止在多个地方查找。

方案3(应用加载优化):

您可能会考虑的是,如果您使用捆绑器,您可能只想在需要时才需要特殊用途的 gem。例如,如果您在应用程序的一个模块中使用路边 gem,请将其添加到加载模块的文件顶部:

require 'curb'
Run Code Online (Sandbox Code Playgroud)

并更改您的 Gemfile,使线路加载路缘看起来像这样:

gem 'curb', require: false
Run Code Online (Sandbox Code Playgroud)

应用程序启动时加载的 gem 越少,加载速度就越快。自动要求功能很棒,但经常被遗忘并被视为理所当然。它所带来的改变是令人惊奇的。