From: Pierre Barbier de Reuille Date: 2006-07-17T04:51:45+09:00 Subject: Re: [QUIZ] Negative Sleep (#87) --------------090203040309040801070102 Content-Type: text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: 7bit Well, as everybody are sending in solutions here are mines ... The first one (sleep1.rb) simply takes the computations, order them, and consider the time to sleep is between the end of the previous and the beginning of the next. The second one (sleep3.rb) takes the same arguments but sleep according to the *beginning* time of each set of operations. All the operations supposed to begin at the same time will happen in the order they were defined (i.e. we have one thread per beginning) At last, the third one (sleep4.rb) uses one thread per computation, hence there is no predictability in the order of computation for operations which are suppose to begin at the same time. Attached also, a test file ... just change the require to test each module. Pierre --------------090203040309040801070102 Content-Type: text/plain; name="sleep1.rb" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="sleep1.rb" class Sleep attr_reader :time def initialize time @time = time end def <<(comp) if Sleep === comp @time += comp.time self else Comp.new(time) << comp end end end class Comp Op = Struct.new :time, :op attr_reader :ops def initialize(time = 0, &block) @ops = [] @ops << Op.new(time, block) if block @time = time end def <<(comp) case comp when Sleep t = comp.time @time += t when Comp @ops.concat comp.ops.map { |o| Op.new(o.time+@time, o.op) } when Proc @ops << Op.new(@time, comp) end self end def run h = Hash.new { |h,k| h[k] = [] } @ops.each do |c| h[ c.time ] << c.op end order = h.keys.sort time = order[0] ref_time = time order.each do |t| sleep(t-time) h[t].each { |b| b.call(t) } time = t end end end --------------090203040309040801070102 Content-Type: text/plain; name="sleep3.rb" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="sleep3.rb" class Sleep attr_reader :time def initialize time @time = time end def <<(comp) if Sleep === comp @time += comp.time self else Comp.new(time) << comp end end end class Comp attr_reader :ops def initialize(time = 0, &block) @ops = Hash.new { |h,k| h[k] = [] } @ops[time] << block if block @time = time end def <<(comp) case comp when Sleep @time += comp.time when Comp comp.ops.each { |t,bs| @ops[t+@time].concat bs } when Proc @ops[@time] << comp end self end def run ref_time = @ops.keys.min ts = @ops.map do |t,bs| Thread.new(bs) do |bs| sleep(t-ref_time) bs.each { |b| b.call(t) } end end ts.each { |t| t.join } end end --------------090203040309040801070102 Content-Type: text/plain; name="sleep4.rb" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="sleep4.rb" class Sleep attr_reader :time def initialize time @time = time end def <<(comp) if Sleep === comp @time += comp.time self else Comp.new(time) << comp end end end class Comp attr_reader :ops def initialize(time = 0, &block) @ops = Hash.new { |h,k| h[k] = [] } @ops[time] << block if block @time = time end def <<(comp) case comp when Sleep @time += comp.time when Comp comp.ops.each { |t,bs| @ops[t+@time].concat bs } when Proc @ops[@time] << comp end self end def run ref_time = @ops.keys.min ts = @ops.map do |t,bs| bs.map do |b| Thread.new(b) do |b| sleep(t-ref_time) b.call t end end end ts.flatten.each { |t| t.join } end end --------------090203040309040801070102 Content-Type: text/plain; name="test_sleep.rb" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="test_sleep.rb" require "sleep1" puts "Test 1" c = Comp.new { |t| sleep 1; puts "#{t} :: Foo here" } << Sleep.new(-1) << Comp.new { |t| puts "#{t} :: Bar there" } << Sleep.new(1) << Comp.new { |t| puts "#{t} :: Well ..." } << Comp.new { |t| puts "#{t} :: Why not" } << Sleep.new(-2) << Comp.new { |t| puts "#{t} :: Just another test" } << Sleep.new(2.5) << Comp.new { |t| puts "#{t} :: A last one ?" } c.run puts "Test 2" c = Comp.new { |t| sleep 1; puts "#{t} :: Foo here" } << Sleep.new(-1) << Comp.new { |t| puts "#{t} :: Bar there" } << Sleep.new(2) << Comp.new { |t| puts "#{t} :: Well ..." } << Comp.new { |t| puts "#{t} :: Why not" } << Sleep.new(-3) << Comp.new { |t| puts "#{t} :: Just another test" } c.run puts "Test 3" c = Comp.new(10) { |t| sleep 1; puts "#{t} :: Foo here" } << Sleep.new(-1) << lambda { |t| puts "#{t} :: Bar there" } << ( Sleep.new(2) << Comp.new { |t| puts "#{t} :: Well ..." } << Comp.new { |t| puts "#{t} :: Why not" } << Sleep.new(-3) << Comp.new { |t| puts "#{t} :: Just another test" } ) << Sleep.new(1.5) << Comp.new { |t| puts "#{t} :: A last one ?" } c.run --------------090203040309040801070102--