Eldritch
The dark arts of concurrent programming.
A DSL that adds parallel programming constructs to make your life a little easier.
Usage
- Install it
gem install eldritch
- Require it
require 'eldritch'
- Use it (see features below)
By default eldritch will inject the DSL into the global scope. If you don't want
this, you can require eldritch/safe
instead of eldritch
.
require 'eldricth/safe'
class MyClass
include Eldritch::DSL
extend Eldritch::DSL
# The DSL is available in this class
end
Development
Setup
bundler install
Running tests
bundler exec rake
Running examples
ruby -I lib examples/{your favorite example}.rb
Generate doc
bundle exec rake doc
Features
async methods
Async methods run concurrently when called. The caller is returned control right away and the method runs in the background.
require 'eldritch'
# define an async method
async def send_email(email)
# ...
end
send_email(some_email) # runs in the background
ruby 1.9.3 and 2.0.0
For all versions of ruby before 2.1.0, you need to define async methods like so:
def foo
# stuff
end
async :foo
Since ruby 2.1.0, def returns the name of the method defined as a symbol. This
allows for the cleaner async def foo
syntax.
async blocks
Async blocks are run concurrently.
require 'eldritch'
async do
# runs in the background
end
tasks
Async blocks and async methods both return tasks. These can be used to interact with the async block/method.
require 'eldritch'
task = async do
# calculate something that will take a long time
end
# we need to result of the task
res = 2 + task.value # waits for the task to finish
together blocks
Together blocks are used to control all async blocks and methods within them as a group. Before exiting, together blocks wait for all their async calls to be done before returning.
require 'eldritch'
together do
1000.times do
async do
# do some work
end
end
end
# all 1000 tasks are done
These blocks can also take an argument. This argument is a group that can be used to control the async calls in the block. See the documentation for Eldritch::Group for more information.
require 'eldritch'
together do |group|
5.times do
async do
# do something
group.interrupt if some_condition # stops all other tasks
end
end
end
A note on GIL
MRI has this nasty little feature called a GIL or Global Interpreter Lock. This lock makes it so that only one thread can run at a time. Let's say that you have 4 cores, running threaded code on MRI will only make use of 1 core. Sometimes, you might not gain a speed boost if you make code parallel. This could the case even if theory says otherwise.
Not all ruby implementations use a GIL. For example, jRuby does not use a GIL.
If your ruby implementation has a GIL, you will probably see a speed boost if your code does a lot of IO or anything that's blocking. In that case running on a single core is not that much of a hindrance, because most of the threads will be blocked and your code should run more often.