EventMachine (EM) adds two different formalisms for lightweight concurrency to the Ruby programmer’s toolbox: spawned processes and deferrables. This note will show you how to use them.

What is Lightweight Concurrency?

We use the term “Lightweight Concurrency” (LC) to refer to concurrency mechanisms that are lighter than Ruby threads. By “lighter,” we mean: less resource-intensive in one or more dimensions, usually including memory and CPU usage. In general, you turn to LC in the hope of improving the performance and scalability of your programs.

In addition to the two EventMachine mechanisms we will discuss here, Ruby has at least one other LC construct: Fibers, which are currently under development in Ruby 1.9.

The technical feature that makes all of these LC mechanisms different from standard Ruby threads is that they are not scheduled automatically.

When you create and run Ruby threads, you can assume (within certain constraints) that your threads will all be scheduled fairly by Ruby’s runtime. Ruby itself is responsible for giving each of your threads its own share of the total runtime.

But with LC, your program is responsible for causing different execution paths to run. In effect, your program has to act as a “thread scheduler.” Scheduled entities in LC run to completion and are never preempted. The runtime system has far less work to do since it has no need to interrupt threads or to schedule them fairly. This is what makes LC lighter and faster.

You’ll learn exactly how LC scheduling works in practice as we work through specific examples.

EventMachine Lightweight Concurrency

Recall that EM provides a reactor loop that must be running in order for your programs to perform event-driven logic. An EM program typically has a structure like this:

 require 'eventmachine'

 # your initializations

 EM.run {
     # perform event-driven I/O here, including network clients,
     # servers, timers, and thread-pool operations.
 }

 # your cleanup
 # end of the program

EventMachine#run executes the reactor loop, which causes your code to be called as events of interest to your program occur. The block you pass to EventMachine#run is executed right after the reactor loop starts, and is the right place to start socket acceptors, etc.

Because the reactor loop runs constantly in an EM program (until it is stopped by a call to EventMachine#stop), it has the ability to schedule blocks of code for asynchronous execution. Unlike a pre-emptive thread scheduler, it’s NOT able to interrupt code blocks while they execute. But the scheduling capability it does have is enough to enable lightweight concurrency.

For information on Spawned Processes, see the separate document SPAWNED_PROCESSES.

For information on Deferrables, see the separate document DEFERRABLES.

[SIDEBAR]: I Heard That EventMachine Doesn’t Work With Ruby Threads.

This is incorrect. EM is fully interoperable with all versions of Ruby threads, and has been since its earliest releases.

It’s very true that EM encourages an “evented” (non-threaded) programming style. The specific benefits of event-driven programming are far better performance and scalabiity for well-written programs, and far easier debugging.

The benefit of using threads for similar applications is a possibly more intuitive programming model, as well as the fact that threads are already familiar to most programmers. Also, bugs in threaded programs often fail to show up until programs go into production. These factors create the illusion that threaded programs are easier to write.

However, some operations that occur frequently in professional-caliber applications simply can’t be done without threads. (The classic example is making calls to database client-libraries that block on network I/O until they complete.)

EventMachine not only allows the use of Ruby threads in these cases, but it even provides a built-in thread-pool object to make them easier to work with.

You may have heard a persistent criticism that evented I/O is fundamentally incompatible with Ruby threads. It is true that some well-publicized attempts to incorporate event-handling libraries into Ruby were not successful. But EventMachine was designed from the ground up with Ruby compatibility in mind, so EM never suffered from the problems that defeated the earlier attempts.

[SIDEBAR]: I Heard That EventMachine Doesn’t Work Very Well On Windows.

This too is incorrect. EventMachine is an extension written in C++ and Java, and therefore it requires compilation. Many Windows computers (and some Unix computers, especially in production environments) don’t have a build stack. Attempting to install EventMachine on a machine without a compiler usually produces a confusing error.

In addition, Ruby has a much-debated issue with Windows compiler versions. Ruby on Windows works best with Visual Studio 6, a compiler version that is long out-of-print, no longer supported by Microsoft, and difficult to obtain. (This problem is not specific to EventMachine.)

Shortly after EventMachine was first released, the compiler issues led to criticism that EM was incompatible with Windows. Since that time, every EventMachine release has been supplied in a precompiled binary form for Windows users, that does not require you to compile the code yourself. EM binary Gems for Windows are compiled using Visual Studio 6.

EventMachine does supply some advanced features (such as Linux EPOLL support, reduced-privilege operation, UNIX-domain sockets, etc.) that have no meaningful implementation on Windows. Apart from these special cases, all EM functionality (including lightweight concurrency) works perfectly well on Windows.

[Validate]

Generated with the Darkfish Rdoc Generator 1.1.6.