Skip to content

Instantly share code, notes, and snippets.

@MarkBennett
Created November 20, 2012 04:05
Show Gist options
  • Save MarkBennett/4115894 to your computer and use it in GitHub Desktop.
Save MarkBennett/4115894 to your computer and use it in GitHub Desktop.
Celluloid Talk
_____ _ _ _ _ _
/ __ \ | | | | | (_) | |
| / \/ ___| | |_ _| | ___ _ __| |
| | / _ \ | | | | | |/ _ \| |/ _` |
| \__/\ __/ | | |_| | | (_) | | (_| |
\____/\___|_|_|\__,_|_|\___/|_|\__,_|
> Painless multithreaded programming for Ruby <
_____ _ _ ___
|_ _| | | | |__ \
| | | |__ _ __ ___ __ _ __| |___ ) |
| | | '_ \| '__/ _ \/ _` |/ _` / __|/ /
| | | | | | | | __/ (_| | (_| \__ \_|
\_/ |_| |_|_| \___|\__,_|\__,_|___(_)
require 'thread'
mutex = Mutex.new
count1 = count2 = 0
difference = 0
a = Thread.new {
loop do
mutex.synchronize do
count1 += 1
count2 += 1
end
end
}
spy = Thread.new {
loop do
mutex.synchronize do
difference += (count1 - count2).abs
end
end
}
_____ _ _ _
|_ _| | | | | |
| | | |__ _ __ ___ __ _ __| |___| |
| | | '_ \| '__/ _ \/ _` |/ _` / __| |
| | | | | | | | __/ (_| | (_| \__ \_|
\_/ |_| |_|_| \___|\__,_|\__,_|___(_)
* Mutexes, locks, conditional variables
* Confusing and hard to debug
_ _ _____ _____ _ _ ______ _____ ___ ______ _____
| \ | | _ | |_ _| | | || ___ \ ___|/ _ \| _ \/ ___|
| \| | | | | | | | |_| || |_/ / |__ / /_\ \ | | |\ `--.
| . ` | | | | | | | _ || /| __|| _ | | | | `--. \
| |\ \ \_/ / | | | | | || |\ \| |___| | | | |/ / /\__/ /
\_| \_/\___/ \_/ \_| |_/\_| \_\____/\_| |_/___/ \____/
___ _ ___ ___ _ _____ ___
/ _ \ | \ | \ \ / / | | |/ _ \ \ / / |
/ /_\ \| \| |\ V /| | | / /_\ \ V /| |
| _ || . ` | \ / | |/\| | _ |\ / | |
| | | || |\ | | | \ /\ / | | || | |_|
\_| |_/\_| \_/ \_/ \/ \/\_| |_/\_/ (_)
* Unless you use jRuby, Rubinius, et al.
_____ _ _ ___
| _ | | | (_) |__ \
| | | |_ __ | |_ _ ___ _ __ ___ ) |
| | | | '_ \| __| |/ _ \| '_ \/ __|/ /
\ \_/ / |_) | |_| | (_) | | | \__ \_|
\___/| .__/ \__|_|\___/|_| |_|___(_)
| |
|_|
_____ _ _ _
|_ _| | | | | | |
| | _ __ ___ _ __ ___ _ _| |_ __ _| |__ | | ___
| || '_ ` _ \| '_ ` _ \| | | | __/ _` | '_ \| |/ _ \
_| || | | | | | | | | | | |_| | || (_| | |_) | | __/
\___/_| |_| |_|_| |_| |_|\__,_|\__\__,_|_.__/|_|\___|
* Lisp, Clojure style
* Just don't share any state and things are easy
* Most Ruby code isn't written to work this way
_____ _ ______ _
| ___| | | | ___ \ | |
| |____ _____ _ __ | |_ | |_/ /___ __ _ ___| |_ ___ _ __
| __\ \ / / _ \ '_ \| __| | // _ \/ _` |/ __| __/ _ \| '__|
| |___\ V / __/ | | | |_ | |\ \ __/ (_| | (__| || (_) | |
\____/ \_/ \___|_| |_|\__| \_| \_\___|\__,_|\___|\__\___/|_|
* node.js, EventMachine, Golliath
* Make everything events in a continuous queue
* Mostly still single threaded, multi-process
* Lots of callbacks
* One large event handler wrecks the whole show
___ _ ______ _ _
/ _ \ | | | ___ \ | | | |
/ /_\ \ ___| |_ ___ _ __ | |_/ /_ _| |_| |_ ___ _ __ _ __ ___
| _ |/ __| __/ _ \| '__| | __/ _` | __| __/ _ \ '__| '_ \/ __|
| | | | (__| || (_) | | | | | (_| | |_| || __/ | | | | \__ \
\_| |_/\___|\__\___/|_| \_| \__,_|\__|\__\___|_| |_| |_|___/
* Erlang, Celluloid, ATOM in Python
* Actors send and receive messages
* Queue up messages in mailboxes
* Actors are supervised
_____ _
| ___| | |
| |____ ____ _ _ __ ___ _ __ | | ___ ___
| __\ \/ / _` | '_ ` _ \| '_ \| |/ _ \/ __|
| |___> < (_| | | | | | | |_) | | __/\__ \
\____/_/\_\__,_|_| |_| |_| .__/|_|\___||___/
| |
|_|
* assume we require 'celluloid' in all examples
* won't show to save some space
___ _
/ _ \ | |
/ /_\ \ ___| |_ ___ _ __ ___
| _ |/ __| __/ _ \| '__/ __|
| | | | (__| || (_) | | \__ \
\_| |_/\___|\__\___/|_| |___/
class Sheen
include Celluloid
def initialize(name)
@name = name
end
def set_status(status)
@status = status
end
def report
"#{@name} is #{@status}"
end
end
charlie = Sheen.new("Charlie")
charlie.set_status("winning") # => "winning"
charlie.report # => "Charlie is winning"
charlie.async.set_status("asynchronously winning") # => nil
charlie.report # => "Charlie is asynchronously winning"
______ _ _
| ___| (_) |
| |_ __ _ _| |_ _ _ __ ___
| _/ _` | | | | | | '__/ _ \
| || (_| | | | |_| | | | __/
\_| \__,_|_|_|\__,_|_| \___|
class JamesDean
include Celluloid
class CarInMyLaneError < StandardError; end
def drive_little_bastard
raise CarInMyLaneError, "that guy's gotta stop. he'll see us"
end
end
james = JamesDean.new
james.drive_little_bastard # James is now dead
james.inspect # Raises attempt to call a dead actor
james = JamesDean.new
james.async.drive_little_bastard # Returns nil
james.inspect # He's still dead though!
_ _ _ _
| | (_) | | (_)
| | _ _ __ | | ___ _ __ __ _
| | | | '_ \| |/ / | '_ \ / _` |
| |___| | | | | <| | | | | (_| |
\_____/_|_| |_|_|\_\_|_| |_|\__, |
__/ |
|___/
* One actor cares about the fate of another
class ElizabethTaylor
include Celluloid
trap_exit :actor_died
def actor_died(actor, reason)
p "Oh no! #{actor.inspect} has died because of a #{reason.class}"
end
end
james = JamesDean.new
liz = ElizabethTaylor.new
liz.link james
james.async.drive_little_bastard # Liz is mortified!
______ _
| ___| | |
| |_ _ _| |_ _ _ _ __ ___ ___
| _| | | | __| | | | '__/ _ \/ __|
| | | |_| | |_| |_| | | | __/\__ \
\_| \__,_|\__|\__,_|_| \___||___/
* Get what you ask for
future = charle.future.report # Create a future
future.value # Block until the future returns a value
class SlowLoris
include Celluloid
def slow_to_move
sleep 5
"Hello!"
end
end
loris = SlowLoris.new
future = loris.future.slow_to_move # The future starts working now
future.value # But doesn't return until now
_____ _ _
/ ___| (_) (_)
\ `--. _ _ _ __ ___ _ ____ ___ ___ _ ___ _ __
`--. \ | | | '_ \ / _ \ '__\ \ / / / __| |/ _ \| '_ \
/\__/ / |_| | |_) | __/ | \ V /| \__ \ | (_) | | | |
\____/ \__,_| .__/ \___|_| \_/ |_|___/_|\___/|_| |_|
| |
|_|
* The show must go on
* Keep your actors in line
supervisor = JamesDean.supervise
james = supervisor.actors.first # => #<Celluloid::Actor(JamesDean:0x96e)>
james.drive_little_bastard # Dead again!
supervisor.actors.first # => #<Celluloid::Actor(JamesDean:0x96f)>
...
supervisor.actors.first # => #<Celluloid::Actor(JamesDean:0x970)>
...
supervisor.actors.first # => #<Celluloid::Actor(JamesDean:0x971)>
______ _
| ___ \ | |
| |_/ /__ ___ | |___
| __/ _ \ / _ \| / __|
| | | (_) | (_) | \__ \
\_| \___/ \___/|_|___/
* Actors love a pool (party!)
class MyWorker
include Celluloid
def add_one(number)
# roflscale computation goes here
number + 1
end
end
pool = MyWorker.pool
i_am_three = pool.add_one(2)
___ ___
| \/ |
| . . | ___ _ __ ___
| |\/| |/ _ \| '__/ _ \
| | | | (_) | | | __/_ _ _
\_| |_/\___/|_| \___(_|_|_)
* http://celluloid.io/
* https://github.com/celluloid/celluloid/wiki
_____ _ _ _
|_ _| | | | | |
| | | |__ __ _ _ __ | | _____| |
| | | '_ \ / _` | '_ \| |/ / __| |
| | | | | | (_| | | | | <\__ \_|
\_/ |_| |_|\__,_|_| |_|_|\_\___(_)
* Tony Arcieri --> https://github.com/tarcieri
* me --> https://twitter.com/markbennett
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment