Skip to content

Instantly share code, notes, and snippets.

@havenwood
Created November 23, 2012 23:19
Show Gist options
  • Save havenwood/4137688 to your computer and use it in GitHub Desktop.
Save havenwood/4137688 to your computer and use it in GitHub Desktop.
Futures and Threads and Bears, oh my!

#Futures and Threads and Bears, oh my!

Celluloid is a lovely concurrency framework that brings Erlang's Actor Model to Ruby. Celluloid is rapidly gaining traction in the Ruby community. (See Sidekiq as a good example of Celluloid in production.)

One of the things that Celluloid implements are Futures:

Ever wanted to call a method "in the background" and retrieve the value it returns later? Celluloid futures do just that. It's like calling ahead to a restaurant to place an order, so they can work on preparing your food while you're on your way to pick it up. When you ask for a method's return value, it's returned immediately if the method has already completed, or otherwise the current method is suspended until the value becomes available.

But as we are all aware, Bears are godless killing machines. So in the spirit of this article's title, lets hack together a Futures-like monstrosity from Ruby's Thread class!

class Future < Thread
  ##
  # For now lets just add a method to check if the Future is ready.
  # If the Thread is dead the Future is ready.
  def ready?
    not alive?
  end
end
#=> nil

The Future starts running right away, but isn't blocking because it is in its own Thread. If we wait until the Future is ready before asking for its value, the value will be returned right away.

future = Future.new do
  3.downto 0 do |n|
    sleep 1
    puts "#{n}..."
  end
  
  'Sekret!!'
end
#=> #<Thread:0x007faea3f6a1b8 sleep>

future.ready?
#=> false

sleep 4
#=> 4

# 3...
# 2...
# 1...
# 0...

future.ready?
#=> true

future.value
#=> "Sekret!!"

If we ask for the Future's value before it is ready, the Thread blocks until the value is available to return.

future = Future.new do
  3.downto 0 do |n|
    sleep 1
    puts "#{n}..."
  end
  
  'Sekret!!'
end
#<Future:0x007faea3d258a8 sleep>

sleep 2
#=> 2

# 3...
# 2...

future.ready?
#=> false

future.value # Blocks until Future is ready.

# 1...
# 0...

#=> "Sekret!!"

THE END.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment