Created
November 10, 2018 18:43
-
-
Save tompave/24c97237d5fd4049e245038ac6bfcf37 to your computer and use it in GitHub Desktop.
Actors and Messages in Ruby
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require "colorize" | |
REGISTRY = {} | |
DEBUG = false | |
SLEEP = 0.5 | |
def register(id) | |
mailbox = Queue.new | |
Thread.current[:process_id] = id | |
REGISTRY[id] = mailbox | |
[id, mailbox] | |
end | |
def mailbox(id) | |
mailbox = REGISTRY[id] | |
unless mailbox | |
raise "Error getting mailbox: unrecognized id #{id}" | |
end | |
mailbox | |
end | |
def new_id | |
@current_id ||= 0 | |
@current_id += 1 | |
end | |
def log(str) | |
return nil unless DEBUG | |
puts str | |
end | |
def current_id | |
Thread.current[:process_id] | |
end | |
def msg_send(to:, from:, msg:) | |
puts "sending <#{msg}> to #{to}, from #{from}".magenta | |
mailbox(to) << { from: from, body: msg } | |
true | |
end | |
def cast(to:, from:, msg:) | |
msg_send(to: to, from: from, msg: msg) | |
end | |
def call(to:, from:, msg:) | |
msg_send(to: to, from: from, msg: msg) | |
receive(block: true) | |
end | |
def receive(block: nil) | |
if block.nil? | |
non_block = (current_id == :main) | |
else | |
non_block = !block | |
end | |
mailbox(current_id).pop(non_block) | |
rescue ThreadError | |
nil | |
end | |
def spawn(&block) | |
id = new_id | |
Thread.new do | |
_id, mailbox = register(id) | |
loop do | |
log "-- id: #{id}, pending messages: #{mailbox.length}" | |
message = receive | |
log "-- id: #{id} received message: #{message}" | |
reply_to = message[:from] | |
body = message[:body] | |
begin | |
sleep SLEEP | |
result = block.call(body, id, reply_to) | |
if result != :noreply | |
msg_send(to: reply_to, from: id, msg: result) | |
end | |
rescue => e | |
msg_send(to: reply_to, from: id, msg: e) | |
end | |
end | |
end | |
id | |
end | |
@aa = spawn do |msg| | |
msg.upcase + "?" | |
end | |
@bb = spawn do |msg| | |
msg.reverse | |
end | |
@cc = spawn do |msg, own_id, from| | |
puts "received msg: #{msg} from: #{from}".yellow | |
if msg == "start" | |
msg_send(to: @aa, from: own_id, msg: "tommaso") | |
msg_send(to: @bb, from: own_id, msg: "tommaso") | |
end | |
:noreply | |
end | |
@ping = spawn do |msg, own_id, from| | |
puts "I'm PING, I've received #{msg}." | |
target = (msg.is_a?(Hash) && msg[:reply_to]) || from | |
msg_send to: target, from: own_id, msg: "PING" | |
:noreply | |
end | |
@pong = spawn do |msg, own_id, from| | |
puts "I'm PONG, I've received #{msg}." | |
target = (msg.is_a?(Hash) && msg[:reply_to]) || from | |
msg_send to: target, from: own_id, msg: "PONG" | |
:noreply | |
end | |
# ------------------------- | |
register(:main) | |
def start | |
msg_send to: @cc, from: :main, msg: "start" | |
end | |
# start | |
# 10.times { |i| msg_send to: @aa, from: :main, msg: "ciao#{i}" } | |
# msg_send to: @ping, from: :main, msg: { reply_to: @pong } | |
# cast to: @bb, from: :main, msg: "tommaso" | |
# call to: @bb, from: :main, msg: "tommaso" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment