Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Celluloid overview

Sean McKibben
September 11, 2012

Celluloid overview

An overview of the actor-based Ruby framework, Celluloid. Includes a basic introduction to why one might want to use Ruby to do threaded programming and what the actor model might provide. Includes a few code examples.

Sean McKibben

September 11, 2012
Tweet

More Decks by Sean McKibben

Other Decks in Programming

Transcript

  1. ’Tis Himself Sean McKibben VP Engineering, Push IO sometimes still

    does contract work Graphex Corp. Designer => Engineer C# => Ruby Flex => Ember.js Pepsi => Coke Cat => Dog Beer => Whiskey Steelcase => Herman Miller Volkswagen => Subaru @graphex Monday, March 18, 13
  2. Stuff that was probably just said Moore’s law and stuff

    Thread.new is not much fun Evented callbacks R fun and reactors are cool Rewriting libs for eventmachine is not so fun Synchrony is kind of awkward and magicky Languages are fun, especially Ruby (but this isn’t Boulder Erlang Group) Monday, March 18, 13
  3. Didn’t EventMachine Tornado Node.Js Already solve this? (I am not

    going to answer this) Monday, March 18, 13
  4. Why actor model? Flexibility Can make threaded stuff and evented

    stuff, and eveaded and thrented whatnots You can make a reactor thread, and then block it, just for fun Pretty easy to tell how to arrange things Monday, March 18, 13
  5. What’s it good for? Sidekiq uses Celluloid to replace many

    Resque workers with a multi-threaded worker I/O Robotics Dealing with situations that are failure-prone Fastering stuff wif cores Monday, March 18, 13
  6. Celluloid is mostly Actor Model Ruby keeps it a bit

    more OOP-y Adds more features like pools Not a member Screen Actors Guild Random computer science reasons (see: wikipedia) Monday, March 18, 13
  7. “Don’t communicate by sharing state; share state by communicating” An

    actor is its own entity that can send and receive messages. Each actor is addressable by any other actor that knows its identifier Actors can create new actors Monday, March 18, 13
  8. Call ’em cells Just like you don’t want mutant cells

    in your body, don’t mutate objects that have gone through the cell wall as messages. This is how celluloid guarantees thread safety. Monday, March 18, 13
  9. But I like calling methods with arguments Cool Each actor

    gets its own thread Method calls to an actor are actually proxied and wrapped in a fiber/thread But it isn’t awkward like synchrony Finally, some code: Monday, March 18, 13
  10. require 'celluloid' class SayActor include Celluloid VOICES = %w(Daniel Emily

    Fiona Jill Karen Lee Moira Samantha Sangeeta Serena Tessa Tom) def initialize(voice=nil) @voice = voice.blank? ? VOICES.shuffle[0] : voice end def say(text) Benchmark.realtime do `say --voice #{@voice} #{text}` end end end Monday, March 18, 13
  11. require 'celluloid' class SayActor include Celluloid VOICES = %w(Daniel Emily

    Fiona Jill Karen Lee Moira Samantha Sangeeta Serena Tessa Tom) def initialize(voice=nil) @voice = voice.blank? ? VOICES.shuffle[0] : voice end def say(text) Benchmark.realtime do `say --voice #{@voice} #{text}` end end end > SayActor.new.say("Hello World") => 1.151892 Boring... Monday, March 18, 13
  12. require 'celluloid' class SayActor include Celluloid VOICES = %w(Daniel Emily

    Fiona Jill Karen Lee Moira Samantha Sangeeta Serena Tessa Tom) def initialize(voice=nil) @voice = voice.blank? ? VOICES.shuffle[0] : voice end def say(text) Benchmark.realtime do `say --voice #{@voice} #{text}` end end end > SayActor.new.async.say("Hello World"); SayActor.new.async.say("Howdy y'all") => nil Fire and forget But no return value... Monday, March 18, 13
  13. require 'celluloid' class SayActor include Celluloid VOICES = %w(Daniel Emily

    Fiona Jill Karen Lee Moira Samantha Sangeeta Serena Tessa Tom) def initialize(voice=nil) @voice = voice.blank? ? VOICES.shuffle[0] : voice end def say(text) Benchmark.realtime do `say --voice #{@voice} #{text}` end end end > SayActor.new.future.say("Hello World").value => 1.768051 Futures capture values and block on #value Back to blocking... Monday, March 18, 13
  14. require 'celluloid' class SayActor include Celluloid VOICES = %w(Daniel Emily

    Fiona Jill Karen Lee Moira Samantha Sangeeta Serena Tessa Tom) def initialize(voice=nil) @voice = voice.blank? ? VOICES.shuffle[0] : voice end def say(text) Benchmark.realtime do `say --voice #{@voice} #{text}` end end end > f = [] > f << SayActor.new.future.say("Howdy y'all") > f << SayActor.new.future.say("Hello World") > f.sum(&:value) => 3.27545 Still Boring... Fully asynchronous with return values Monday, March 18, 13
  15. > speaker_pool = SayActor.pool(:size => 5) => #<Celluloid::Actor(SayActor:0x3fff12631568) @voice="Tom"> >

    speaker_pool.say("hello") => 1.379268 > speaker_pool = SayActor.pool(:size => 30) > speaker_pool.future.say("hi") => #<Celluloid::Future:0x007f9d1c3def58> > future.value => 0.792455 > futures = 100.times.map{|i| speaker_pool.future.say(i)}; futures.sum(&:value) => 183.451935 Pools Monday, March 18, 13
  16. Registry Global directory of actors, so you don’t have to

    pass around instances > Celluloid::Actor[:speaker_pool] = SayActor.pool(:size => 30) > Celluloid::Actor[:speaker_pool].say("hello world") => 1.593524 Monday, March 18, 13
  17. Self Celluloid wraps your class so never pass ‘self’ to

    other actors. Use Celluloid::Actor.current (or if you are in your actor, just Actor.current) to pass the celluloid proxy object instead Monday, March 18, 13
  18. Supervisors Supervisors resurrect dead actors when they crash by creating

    a new instance. > sup = SayActor.supervise_as :overactor => #<Celluloid::Actor(Celluloid::SupervisionGroup:0x3fff112df528) @membe... => 1.245053 > Celluloid::Actor[:overactor].last_words("ahhhghhh") SayActor crashed! RuntimeError: ahhhghhhh > Celluloid::Actor[:overactor].say("Hello") => 0.777873 > Celluloid::Actor[:overactor].last_words("ahhhghhh") SayActor crashed! RuntimeError: ahhhghhhh > Celluloid::Actor[:overactor].say("Hello") => 0.735309 > Celluloid::Actor[:overactor].last_words("ahhhghhh") SayActor crashed! > Celluloid::Actor[:overactor].say("Hello") => 0.794133 Monday, March 18, 13
  19. Gotchas Be on the lookout for thread unsafety Don’t mutate

    the state of objects you pass to other actors (sometimes it is good to marshall data) You shouldn’t need fibers and threads and mutexes any more... Monday, March 18, 13