Ruby has long been criticized in its 1.8 version for its limited Green Thread model. Luc Castera gave a presentation at RubyNation about Concurrent Programming with Ruby and Tuple Spaces. After introducing the different threading model in computer world with their various applications: Ruby 1.8, Ruby 1.9, JRuby, Erlang, Luc introduces Ruby Multiple Processes (Image and quote from the presentation):
- Pros:
- No longer sharing memory
- Take advantage of multiple CPUs (Performance)
- Not all threads are blocked by blocking system calls
- Scalability
- Fault Tolerance
- Cons:
- Process creation, execution and cleanup is expensive
- Uses a lot of memory (loading Ruby VM for every process)
- Need a way for processes to communicate!
There are many options to realize process communication: Database (as it is the case in cluster of application servers (Mongrel, Thin...)), Queues like RabbitMQ (Nanite's solution), DRB, ActiveMQ, ... and TupleSpaces.
Luc compares two TupleSpaces implementations: Rinda and his own Blackboard. A tuple space provides a repository of tuples that can be accessed concurrently. The tuples basically provide 3 access primitives: write (writes a tuple to the tuple space), read (reads a tuple from the tuple space), take (reads and removes a tuple from the tuple space).
Linda is a coordination model which was defined by David Gelernter and Nicholas Carriero to support the concept of global object coordination.
Rinda is the Ruby implementation of Linda, it is a built-in library. A Rinda Tuple might look like this: t1 = [:add, 5, 9]
, which could be interpreted by clients as a task to add up the given numbers.
The main drawback of Rinda is that it's not persistent, you lose all tuples in the space when it is stopped or when it crashes.
That's what Luc tried to address by developing Blackboard. It is a TupleSpace implementation on top of the key-value database Redis, which makes it possible to have persistence.
[Redis] is similar to memcached but the dataset is not volatile, and values can be strings, exactly like in memcached, but also lists and sets with atomic operations to push/pop elements
Here is a sample use of the API:
ts = Blackboard::TupleSpace.new ts.write [:calculator, :add, 1, 2] ts.take [:calculator, :add, nil, nil]
A benchmark shows the difference between Rinda and Blackboard (from the presentation):
Rinda | Blackboard | |
Write (1000) | 0.042749 | 0.253068 |
Take (500) | 0.082744 | 15.844250 |
Read (500) | 0.020098 | 20.098478 |
The current implementation is the first iteration and Luc has plans to move from Redis to a custom based Erlang Blackboard implementation which should be easily called from thirdparty languages like Ruby.