在多进程 fork 服务器中,'require' 比 'autoload' 和 Ruby 2 更可取吗?

Is 'require' preferrable to 'autoload' with Ruby 2 in a multi-process fork server?

我正在阅读 this 文章。我关心的是 autoload 对比 require 的好处。通过阅读这篇文章,我了解到对多线程服务器使用 autoload 是不好的,因为一个线程可能会尝试加载一个不在内存中的对象。

文章说多进程服务器呢?自动加载对那些有好处吗?然后它说这取决于。如果服务器使用 fork(它为每个请求生成一个新进程),例如 Phusion Passenged,而您使用的是 Ruby 2,那么自动加载就没有好处。

原因是因为Ruby 2 使用了写时复制语义。这意味着使用 requireautoload 更好。使用写时复制语义,如果我们在启动时加载 Foo::Bar,我们将在所有进程之间共享一份 Foo::Bar。因此,不会有很大的内存占用。

但是,如果我们不使用 Ruby 2 并且我们不使用使用 fork 的多进程服务器,则每个进程最终将加载自己的 Foo::Bar 副本,这可能会导致更高的内存使用率。因此,在那种情况下 autoload 优于 require.

我对文章的解读是否正确?

我想你已经明白了,但为了清楚起见,最好重申几点:

  1. 重要的区别不完全在 requireautoload 之间,而是在预加载和延迟加载之间。预加载在分叉时是线程安全和内存高效的,但它会减慢服务器启动速度。延迟加载在分叉时既不是线程安全的也不是内存有效的,但它允许快速服务器启动。 requireautoload 以及 Rails eager_autoload 预加载; autoload 本身延迟加载。

  2. 考虑到上述情况,不同的服务器和 Ruby 版本会针对延迟加载和急切加载提出不同的问题:

    • 在线程服务器中,延迟加载是不安全的,因此需要(咳咳)预加载。
    • 在事件服务器中,延迟加载是可以的,所以你也可以延迟加载来快速启动服务器。
    • 在分叉服务器中,延迟加载是安全的,但内存效率低下。
      • 在 Ruby < 2 中,预先加载也是内存效率低下的,因为 Ruby < 2 不支持写时复制。所以你不妨延迟加载。 (实际上,你应该做的是升级到当前 Ruby。)
      • 在 Ruby >= 2 中,预先加载是内存高效的,因为它利用了写时复制的优势,因此是首选。