Skip to content

Instantly share code, notes, and snippets.

@olleolleolle
Created February 25, 2017 18:55
Show Gist options
  • Select an option

  • Save olleolleolle/ddd12626d8651b256531b97880334620 to your computer and use it in GitHub Desktop.

Select an option

Save olleolleolle/ddd12626d8651b256531b97880334620 to your computer and use it in GitHub Desktop.
Example Celluloid program which used to crash JRuby. See https://github.com/celluloid/celluloid/issues/677
require "rubygems"
require "celluloid"
require "pry"
module Enumerable
class ComutativeReducerActor
include Celluloid
def initialize(enumerable, reducer)
@enumerable = enumerable
@n_active_actors = 0
@available_actors = []
@reducer = reducer
end
def wait_for_reduction
@condition = Celluloid::Condition.new
Actor.current.async.reduce
result = @condition.wait(9_000_000)
result
end
def reduce
return if @n_active_actors > 4
if @enumerable.size == 1 && @n_active_actors == 0
@condition.signal(@enumerable.first)
return
elsif @enumerable.size >= 2
pair = @enumerable[0..1]
@enumerable = @enumerable[2..-1]
@enumerable ||= []
process_pair pair
Actor.current.async.reduce
end
end
def process_pair(pair)
@n_active_actors += 1
reducer = \
if @available_actors.empty?
SingleReducer.new pair: pair, reducer: @reducer, parent: Actor.current
else
a = @available_actors.first
@available_actors = @available_actors[1..-1]
@available_actors ||= []
a.tap do |a1|
a1.pair = pair
a1.parent = Actor.current
end
end
reducer.async.reduce
end
def add_new_value(value, actor)
@enumerable << value
if (@enumerable.size / 4) > @available_actors.size
@available_actors << actor
else
actor.terminate
end
@n_active_actors -= 1
Actor.current.async.reduce
end
end
class SingleReducer
include Celluloid
attr_accessor :pair
attr_accessor :parent
def initialize(pair: nil, reducer: nil, parent: nil)
@pair = pair
@reducer = reducer
@parent = parent
end
def reduce
result = nil
result = if @pair.size == 1
@pair.first
else
@reducer.call @pair.first, @pair.last
end
@parent.async.add_new_value(result, Actor.current)
end
end
def comutative_reduce(&reducer)
reducer = ComutativeReducerActor.new(self, reducer)
val = reducer.wait_for_reduction
reducer.terminate
val
end
end
result = ([1, 2, 4, 5, 6] * 100).comutative_reduce do |a, b|
a * b
end
puts result
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment