Created
October 2, 2020 05:32
-
-
Save wycleffsean/2ee5bf9f55ab8c70f6e010e6679c77e8 to your computer and use it in GitHub Desktop.
Cooperative concurrency in ruby
This file contains 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 'fiber' | |
class EventLoop | |
def initialize | |
@tasks = {} | |
@state = {} | |
end | |
def call(&block) | |
instance_eval &block | |
loop do | |
@tasks.each { |name, fiber| | |
unless fiber.alive? | |
@tasks.delete(name) | |
next | |
end | |
fiber.resume | |
} | |
end | |
end | |
def task(name, &block) | |
@tasks[name] = Fiber.new do | |
instance_eval(&block) | |
end | |
end | |
def set(key, value) | |
@state[key] ||= [] | |
@state[key] << value | |
Fiber.yield | |
end | |
def get(key, *args) | |
loop do | |
return @state[key].pop if @state.key?(key) && @state[key].any? | |
Fiber.yield | |
end | |
end | |
end | |
# A cooperatively concurrent restaurant | |
EventLoop.new.call do | |
task :open_restaurant do | |
set(:free_table, 1) | |
set(:free_table, 2) | |
end | |
task :server do | |
loop do | |
puts "server - setting table" | |
table = get(:free_table) | |
set(:table, table) | |
puts "server - giving menu" | |
set(:menu, '...') | |
puts "server - taking order" | |
order = get(:order) | |
puts "server - sending #{order} order to kitchen" | |
set(:kitchen_order, order) | |
puts "server - serving #{order}" | |
order = get(:ready_order) | |
set(order, order) | |
end | |
end | |
task :chef do | |
loop do | |
order = get(:kitchen_order) | |
puts "chef - making #{order}" | |
set(:ready_order, order) | |
end | |
end | |
task :customer1 do | |
puts "customer 1 - waiting for table" | |
table = get(:table) | |
puts "customer 1 - waiting for menu" | |
get(:menu) | |
puts "customer 1 - ordering" | |
set(:order, :filet_mignon) | |
order = get(:filet_mignon) | |
puts "customer 1 - finished #{order}" | |
set(:free_table, table) | |
end | |
task :customer2 do | |
puts "customer 2 - waiting for table" | |
table = get(:table) | |
puts "customer 2 - waiting for menu" | |
get(:menu) | |
puts "customer 2 - ordering" | |
set(:order, :lobster_bisque) | |
order = get(:lobster_bisque) | |
puts "customer 2 - finished #{order}" | |
set(:free_table, table) | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment