131 lines
5.6 KiB
Plaintext
131 lines
5.6 KiB
Plaintext
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 scalability 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.
|
|
|