Donato Donato - 4 months ago 9x
Ruby Question

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

I am reading this article. My concern is the benefits of

. From reading the article, what I gather is that using
for multi-threaded servers is bad because one thread might try to load an object that is not in memory yet.

The article says what about multi-process servers? Is autoload good for those? Then it says it depends. If the server uses fork (which spawns a new process for each request), such as Phusion Passenged, and you are using Ruby 2, then autoload is not beneficial.

The reason is because Ruby 2 uses copy-on-write semantics. This means it is better to use
. With copy-on-write semantics, if we load
on boot, we will have one copy of
shared between all processes. Hence, there will be no big memory footprint.

However, if we are not using Ruby 2 and we are not using a multi-process server that uses fork, each process will end up loading its own copy of
possibly leading to higher memory usage. Therefore, in that case
is preferrable to

Is my interpretation of the article correct?


I think you've got it, but it would be good to restate a couple of points to be clear:

  1. The important distinction isn't quite between require and autoload but between eager and lazy loading. Eager loading is thread-safe and memory efficient when forking, but it slows server startup. Lazy loading is neither thread-safe nor memory efficent when forking, but it allows fast server startup. require or autoload together with Rails eager_autoload eager load; autoload by itself lazy loads.

  2. With the above in mind, different servers and Ruby versions raise different issues for lazy and eager loading:

    • In a threading server, lazy loading is unsafe, so eager loading is (ahem) required.
    • In an evented server, lazy loading is fine, so you might as well lazy-load for fast server startup.
    • In a forking server, lazy loading is safe but memory-inefficient.
      • In Ruby < 2, eager loading is also memory-inefficient, since Ruby < 2 doesn't support copy-on-write. So you might as well load lazily. (Actually, what you should do is upgrade to current Ruby.)
      • In Ruby >= 2, eager loading is memory-efficient, since it takes advantage of copy-on-write, and therefore preferred.