Background
Rubinius is shaping up to be quite a nice platform for networking and distributed computing. The virtual machine uses libev at the foundation, which provides a high performance event loop, timers, and high speed, asynchronous IO using epoll and kqueue. A lot of this functionality is utilized through the Channel class, an elegant mechanism that comes from the π-calculus that serves a number of roles in Rubinius.
Channel
First, you can treat a Channel like a thread safe queue that lets you push an item onto the tail from any thread, and then receive the item at the head from any thread:
c = Channel.new
Thread.new do
c.send "foo"
end
Thread.new do
puts c.receive
end
Unless you schedule a timeout (e.g. Scheduler.send_in_seconds(...)) the call to Channel#receive will block until a new item is available. If multiple threads are blocked on the same channel then they will be unblocked one at a time, in the order of arrival, as new items become available. This functionality means the Channel can also serve as a mutex:
lock = Channel.new
#...
lock.receive
begin
run_shared_code
ensure
lock << nil
end
or when sharing a set of resources a Channel can act as a counting semaphore. Say a pool of threads are sharing a limited number of database connections:
# Initialize the semaphore by writing a value per available resource
sem = Channel.new
NUM_CONNECTIONS.times { sem << nil }
#...
NUM_THREADS.times do
Thread.new do
sem.receive
begin
do_db_stuff
ensure
sem << nil
end
end
end
So this is all pretty cool, but everyone knows that multi-threaded programming is just error prone. In simple situations where you don't need to share resources between threads it's not so tricky, but for more complex occasions threads can get really tough. Beyond that, if you try to uses multiple threaded libraries you can run into extremely difficult to debug problems.
Actors
One answer to this problem is the actor model. In this model an actor is a process that comes with a special mailbox. Actors communicate by sending messages to each other, and on reception of a message they can do local processing, send more messages, or spawn additional actors. Besides sending messages actors should not access any shared resources, which greatly simplifies the concurrency problems that can arise. Additionally, it makes it easy to run actors in parallel on multi-core machines, or across a network on multiple boxes.
Current Status
Rubinius has initial support for local actors now, and we are working on building them up to be the foundation for a full fledged distributed computing framework. This is an outline of the currently envisioned design:
Actor
A lightweight thread with a mailbox.
VMManager
An Actor that accepts inter-vm messages over a Channel, and then forwards them on to whichever Actor they are destined for within its VM instance.
NodeManager
An Actor that accepts inter-process messages over a Socket, and then forwards them on to whichever VM they are destined for within its process.
VMActorProxy
A proxy object that lets actors transparently send messages to other actors that are located on another VM instance within the same process. This proxy is created as necessary whenever an Actor is received across a VM boundary, whether through a mailbox message or by looking up a named service.
NetActorProxy
A proxy object that lets actors transparently send messages to other actors that are located in another process, typically across a network. This proxy is created as necessary whenever an Actor is received across a process boundary, whether through a mailbox message or by looking up a named service.
Create your profile
Help contribute to this project by taking a few moments to create your personal profile. Create your profile »
0.10—69% complete
Completed 9 of 13 tickets
Pages
- Home
- FAQ
- IRC Info and Who's Who
- Releases
- Using Git
- Installation
- Getting Started
- Common Build Problems and Solutions
- Howto - Contribute
- Howto - Write a ticket
- Howto - Run my Rails app with Rubinius
- Howto - Write a Ruby spec
- Howto - Write a Rubinius spec
- Howto - Fix a failing spec
- Howto - Develop with a separate RubySpec repo
- Howto - Debug shotgun
- The Rubinius specs
- Shotgun - The Rubinius Virtual Machine
- Developer Readme
- Core Library - Coding Guidelines
- Coding Style Guide
- Contributor Platforms
- Stuff to read
- Extending Standard Library Specs
- Improve Gem Support in Rubinius
- Actors - Concurrent Rubinius
- FFI or Foreign Function Interface
