From: Tony Arcieri Date: 2008-01-23T10:31:31+09:00 Subject: Re: Announcing Revactor: an Actor model implementation for Ruby 1.9 ------=_Part_16291_9309691.1201051896814 Content-Type: text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: 7bit Content-Disposition: inline On Jan 22, 2008 4:39 PM, aemadrid@gmail.com wrote: > I'm still trying to wrap my head around this whole concept. What is > the difference in approach between Revactor and EventMachine [1]? I > can see that one works with 1.8 and the other starts with 1.9 but they > seem to me, the uneducated reader, very similar. Am I missing > something? > Revactor implements the Actor model and EventMachine implements the Reactor pattern (hmm, Reactor, Revactor, a little confusing I'm sure. My bad). The similarities between Actor and Reactor do go much deeper than their names. Both provide ways of programming performant and highly concurrent network applications. The main drawback of Reactor I've encountered is that it's fully asynchronous and relies on inversion of control. That's not to say this is a bad thing: it's great for anything that does event processing, particularly of incoming messages. However, Actors also support this style of programming. For more information see the Revactor::TCP documentation on active mode. The main advantage of Actor over Reactor in this regard involves APIs which require synchronous interfaces and just won't work without them. Perhaps the best example of this I can think of is ActiveRecord. With a simple Foo.find(:first).bar.baz you've traversed across two associations which each made their own query and blocked until they had the results, because the next method invocation needed it. It's not the most efficient approach in the world, but it's there when you need it. Unfortunately, it's just not possible on top of a Reactor API, but works fine on top of Actors. Using Reactor means you must abandon any code which is structured around making synchronous blocking calls to interact with the network. This includes pretty much everything built on the traditional imperative sockets API. Everything must use an asynchronous API. There are ways around this, such as spinning off any synchronous blocking calls in a separate thread, but then you need a thread for each blocking call you wish to make, and there are performance issues with threads and I/O in Ruby, not to mention the traditional pitfalls of threaded programming. With Actors, you can pull in any code that uses the existing Sockets API, (monkey)patch in Revactor::TCP::Sockets in their place, and you're good to go. You can mix and match synchronous and asynchronous programming without ever having to involve threads. Perhaps the biggest argument for Actors is how many network applications end up being structured internally. Time and time again the optimal architecture seems to be discrete components which communicate with message passing. For an idea of this, have a look at a digram of qmail: http://www.nrg4u.com/qmail/the-big-qmail-picture-103-p1.gif http://www.nrg4u.com/qmail/the-big-qmail-picture-103-p2.gif Qmail is implemented as a number of C programs which communicate using pipes. Reactor also works well with this approach: implement each component as a process, and have them communicate using pipes, sockets, etc. The Actor model is built around the idea of discrete components which communicate using message passing, but gets rid of the headaches involved with process invocation, setting up IPC channels, etc. Rather than being a heavyweight OS process, each discrete component is a lightweight Ruby Fiber. This means building systems which rely on independent components which communicate with message passing is both lightweight and performant. -- Tony Arcieri ClickCaster, Inc. tony@clickcaster.com ------=_Part_16291_9309691.1201051896814--