From: Tony Arcieri Date: 2011-07-13T00:23:07+09:00 Subject: [ANN] celluloid 0.2.0: a concurrent object framework for Ruby Celluloid is a concurrent object framework for Ruby inspired by Erlang and the Actor Model: - Github: http://github.com/tarcieri/celluloid - RDoc: http://celluloid.github.com/ Celluloid wraps objects in threads, allowing them to run concurrently, while still letting you talk to them using standard Ruby method call conventions, in addition to providing asynchronous calls which run in the background. This release brings with it two powerful new features which extend Celluloid's asynchronous capabilities even further: method futures and signaling. -- Method Futures: All Celluloid objects now respond to the #future method. This method takes the same parameters as #send (e.g. obj.future :method_name, arg1, arg2, arg3) and immediately returns a Celluloid::Future object while the requested method call executes in the background. When you are ready to obtain the value returned from the method, you invoke Celluloid::Future#value, which will automatically block until the method call completes, or will return immediately if the method call has already completed. This provides an easy way to initiate a method call, do something else, and obtain the result at a later point in time. An example use case is scatter/gather operations where you wish to spread a long computation (or an I/O bound operation) across multiple threads, then collect all the results later. Here's some pseudocode demonstrating the concept: objects = (1..10).map { |n| MyCelluloidObject.new(n) } futures = objects.map { |obj| obj.future :do_something_crazy_with_my_number } results = futures.map { |future| future.value } This creates 10 concurrent Celluloid objects each running in their own thread, then initiates the #do_something_crazy_with_my_number. What sort of crazy things could this method do? It could fetch the nth page of Google results for a particular search term. It could try to brute force an MD5 hash with n leading zeroes. The #future method will kick off this long-running computation in an asynchronous, non-blocking manner, allowing the caller to scatter the given method call across 10 different objects, then gather the results by calling future.value on each of the Celluloid::Future objects returned from the original obj.future calls. -- Signaling: Every Celluloid object now responds to the #signal and #wait methods. Each of these methods takes a name as a first parameter. Calling #wait :my_signal_name suspends execution of the current method, allowing it to process other incoming method calls (Celluloid only processes one method at a time and maintains a queue of incoming calls). Another method (or object) can unblock the #waiting method by calling #signal :my_signal_name. #signal optionally accepts a value as a second parameter (e.g. #signal :my_signal_name, 42) which is returned from the corresponding #wait call. Several methods can be #waiting at the same time. This allows objects processing a synchronous call to wait until some outside event occurs before returning a result, similar to ConditionVariables in threaded programming. See the Celluloid README for examples. -- Celluloid now provides asynchronous alternatives to all parts of the method dispatch cycle: - You can "fire and forget", invoking methods asynchronously and ignoring the values they return - You can asynchronously invoke a method and obtain its return value later via a future - Method calls in-progress can voluntarily suspend themselves waiting for an asynchronous signal before returning a value Enjoy! -- Tony Arcieri