[Boulder Ruby Group] Actor model in Ruby 1.9
Tony Arcieri
tony at clickcaster.com
Fri Sep 14 00:12:39 EDT 2007
I did a simple implementation of the Actor model (i.e. Erlang-style
concurrency) using Ruby 1.9's Fibers mechanism. You can check it out here
(if you have Ruby 1.9 installed):
http://pastie.caboo.se/97050
Fibers are coroutines, which means they're like procs, except at any point
they can call Fiber.yield and return control back to the process that
started them. The controlling process can resume them with Fiber.resume
This implementation adds a mailbox to a Fiber, and an Actor.receive method
which runs a filter across the mailbox, wrapping Fiber.yield and calling it
if the filter fails to match any of the messages in the mailbox.
Here's an example of how to use it:
http://pastie.caboo.se/pastes/97049
The basic idea is that you spawn Actors from the main process. Each Actor
has an associated mailbox, and you can asynchronously send it messages (in
this implementation, using <<). When you spawn an actor, you pass it a
block to run. This actually runs within a fiber. In an Actor, you can call
the Actor.receive method to read messages from the mailbox. You specify a
filterset for reading the messages: either an argument to be directly
compared with ===, or a proc that returns true on a match.
A run queue is maintained which contains every single Actor which has
received a message. When an Actor receives a message, its Fiber is resumed,
and then the specified filter set is checked against the mailbox. If
there's a match, the corresponding block is invoked, otherwise the Fiber
yields until its gets another message. If all our Fibers are sleeping,
control is returned back to the main program until it sends a message to one
of the actors.
Actors can make other Actors with the Actor.spawn method and can also send
messages to other Actors, provided they have a handle to the Actor object
they want to send a message to.
If you dump the implementation into actor.rb then paste the example code
into irb, you can play around with it. Just use << to send a message to any
Actor object. Messages are totally arbitrary and get dumped into the
Actor's associated mailbox:
irb(main):040:0> actor2 << :cat
I hate cats... you take it!
I love cats
My buddy got a cat
=> :cat
Here we have messages being sent from actor2 -> actor1 -> buddy. actor2
receives the :cat message and forwards it onto actor1. actor1 receives it
and sends a :gotacat message to buddy. Each line was printed out by a
different fiber.
Here's an example of the Proc-based pattern matching:
irb(main):041:0> actor2 << "Foobar"
I hate strings... you take it!
I got a string: Foobar
=> "Foobar"
Here actor2's proc-based filter detected it received a string, and decided
to forward it back to actor1. actor1's filter was set up to print out
strings it received using a proc to match them.
--
Tony Arcieri
ClickCaster, Inc.
tony at clickcaster.com
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://rubyforge.org/pipermail/bdrg-members/attachments/20070913/f4922489/attachment.html
More information about the Bdrg-members
mailing list