eventmachine and rev

R

Roger Pack

What would you say is the difference between rev and eventmachine?
Thoughts? (Obviously I can see that both work with 1.9, rev only with
1.9).
 
T

Tony Arcieri

[Note: parts of this message were removed to make it a legal post.]

What would you say is the difference between rev and eventmachine?
Thoughts? (Obviously I can see that both work with 1.9, rev only with
1.9).

Rev's main design goal was to minimize C and build upon Ruby's existing
socket APIs and OpenSSL bindings. A lot of the features that allow Rev to
be predominantly Ruby showed up in 1.9, namely the *_nonblock versions of
various Socket methods. For this reason, a lot of C code was needed to
implement these features in Ruby 1.8 (which is how EventMachine solved the
problem), but is no longer necessary in Ruby 1.9.

In Rev. there's two kinds of things: event loops (Rev::Loop) and Watchers
(event observers), which are all derived from the abstract base class
Rev::Watcher. Subclasses of Rev::Watcher translate incoming events to
higher and higher levels of abstraction. The code is factored into lots of
small classes that wrap up common behavior in an inheritence hierarchy, for
example Rev::Sockets and Files are subclassed from Rev::IO, and
Rev::TCPSocket and Rev::UNIXSocket are subclassed from Rev::Socket. I'm
sure this is how EventMachine's C++ code is factored internally, but from
the Ruby perspective much of the functionality appears in the flat
EventMachine namespace, which is a Module that exposes singleton methods
like EM.start_tcp_server, EM.start_unix_server, etc instead of using
objects/inheritance.

Being object oriented makes Rev's API a lot more Ruby-like, and having as
much code as possible in Ruby means it's easier for people to hack on it
since they don't have to know C++. The only things that are C in Rev are
the libev bindings (which let you monitor Ruby IO objects for
readability/writability, and provide timers), a class for doing high-speed
buffered network I/O, and a subclass of OpenSSL::SSL::SSLSocket which adds
nonblocking I/O support. Everything else is written in Ruby.

Building on libev means that the codebase for doing portable,
high-performance cross-platform event monitoring has already undergone a lot
of debugging and performance tuning. There's been a lot of problems with
the EventMachine bindings to epoll, and any improvements to that code will
only come from people interested in EventMachine specifically (who know
C/C++). libev is in use by a number of people, most notably Rubinius.
libev was also written by a performance-obsessed C guru and benchmarks quite
nicely, outperforming libevent.

Unfortunately, I haven't done benchmarks of Rev vs. EventMachine. Maybe
I'll do some when there's an official EventMachine release with Ruby
1.9support. If Rev does outperform EventMachine on Ruby
1.9, it might be interesting to do what libev did for libevent: monkeypatch
some core files of the pure Ruby implementation of EventMachine to use Rev
as their underlying implementation. EventMachine packs support for a lot of
features Rev does not, and is used by many, many projects (including some of
my own) whereas Rev hasn't seen much use yet.

My main motivation for writing Rev was a feature sorely lacking from
EventMachine which was crucial to implementing Revactor: stoppable /
restartable event monitors.

Every subclass of Rev::Watcher supports the following methods:

attach(loop) - monitor this watcher using the given event loop
disable - temporarily disable event reception
enable - re-enable event reception
detach - remove this watcher from the event loop (for when you're done with
a watcher, e.g. when the connection closes, although it's automatic in that
case)

Many features of the Actor API in Revactor depend on being able to
temporarily disable event monitoring. Revactor translates events into
messages which get sent to Actor's mailboxes, so it's important those
messages are only sent when an Actor is expecting them. This means *any*
event source wrapped by the Actor API must be stoppable/restartable, and in
Rev, these features are implemented in the Rev::Watcher base class, so
they're available in every subclass.
 
J

James Gray

A lot of the features that allow Rev to
be predominantly Ruby showed up in 1.9, namely the *_nonblock
versions of
various Socket methods.

Is that true? I thought they were added to the 1.8 branch too.

James Edward Gray II
 
T

Tony Arcieri

[Note: parts of this message were removed to make it a legal post.]

Is that true? I thought they were added to the 1.8 branch too.

Interesting. I wasn't aware of that, but you appear to be correct. That
would make adding 1.8 support to Rev a lot easier.

Well, in addition to the *_nonblock methods, the Rev C extension is using
the rb_thread_blocking_region() function to perform blocking system calls.
In order to work on 1.8 this would need to be removed and replaced with a
workaround that blocks only for short intervals then allows the Ruby
scheduler to run.

There's some other bits which are 1.9 specific which would require
workarounds as well. For example, #instance_exec is used to implement the
ability to define callbacks at runtime, e.g.:

HOST = '127.0.0.1'
PORT = 4321

server = Rev::TCPServer.new(ADDR, PORT) do |c|
c.on_connect { puts "#{remote_addr}:#{remote_port} connected" }
c.on_close { puts "#{remote_addr}:#{remote_port} disconnected" }
c.on_read { |data| write data }
end

server.attach(Rev::Loop.default)

puts "Echo server listening on #{HOST}:#{PORT}"
Rev::Loop.default.run

The on_connect, on_close, and on_read callbacks all use instance_exec to
allow them to execute in the scope of the watcher object (giving access to
remote_addr, remote_port, write, etc.)

Obviously #instance_eval would suffice for on_connect / on_close, but
on_read takes a parameter, as do several other callbacks in the API.
 
R

Roger Pack

readability/writability, and provide timers), a class for doing
high-speed buffered network I/O
Can it buffer incoming I/O?

, and a subclass of OpenSSL::SSL::SSLSocket which
adds
nonblocking I/O support. Everything else is written in Ruby. Nice



as their underlying implementation. EventMachine packs support for a
lot of
features Rev does not, and is used by many, many projects (including
some of
my own) whereas Rev hasn't seen much use yet.
Which features?

Thanks!
 
T

Tony Arcieri

[Note: parts of this message were removed to make it a legal post.]

Can it buffer incoming I/O?

The actual C buffering code has support for buffering incoming I/O with
Rev::Buffer#read_from(io). However, Rev just dispatches any incoming data
it reads as it's read through the on_read callback.

However, read buffering is performed by Revactor, which provides an
imperative, blocking read API, which works just like IO#read

Which features?
Off the top of my head, EventMachine has many protocol adapters including
SMTP and a (separately bundled) evented HTTP server with an associated REST
framework, not to mention Evented Mongrel and Thin. It also implements the
Deferrable pattern for performing blocking calls alongside the event loop.
I'm sure there's many more things I'm omitting here.

Rev bundles an asynchronous DNS client which it uses internally for all DNS
resolution, as well as an HTTP client. Right now there are no HTTP server
bindings for it.

Revactor allows you to run Mongrel on top of Rev using Actors for
concurrency.
 
R

Roger Pack

EM has...
Evented Mongrel and Thin. It also implements

It might well be noted that evented mongrel is something like a 1K patch
to normal mongrel, so not too much :) And, as you suggested, it would
be interesting to use Rev as the driver for EM (drop in replacement) and
see if it worked.
Cheers!
-Roger
 
J

James Gray

Interesting. I wasn't aware of that, but you appear to be correct.
That
would make adding 1.8 support to Rev a lot easier.

Yes, I'm pretty sure EventMachine added a pure Ruby branch after they
were added.

James Edward Gray II
 
R

Roger Pack

Unfortunately, I haven't done benchmarks of Rev vs. EventMachine. Maybe
I'll do some when there's an official EventMachine release with Ruby
1.9support. If Rev does outperform EventMachine on Ruby
1.9, it might be interesting to do what libev did for libevent:
monkeypatch
some core files of the pure Ruby implementation of EventMachine to use
Rev
as their underlying implementation. EventMachine packs support for a
lot of
features Rev does not, and is used by many, many projects (including
some of
my own) whereas Rev hasn't seen much use yet.

Looks like EM supports 1.9. Might want to try them both out speed-wise
sometime :)
-R
 
T

Tony Arcieri

[Note: parts of this message were removed to make it a legal post.]

Looks like EM supports 1.9. Might want to try them both out speed-wise
sometime :)

Let me say right off the bat that Rev is much slower than EventMachine on
Ruby 1.8. Rev used to be faster on Ruby 1.9, but EventMachine has since
gotten support for making blocking system calls on Ruby 1.9 and is, in all
likelyhood, probably faster on 1.9 as well.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,764
Messages
2,569,566
Members
45,041
Latest member
RomeoFarnh

Latest Threads

Top