Α͋͘ΔFibonacci [0, 1] [1, 1] [2, 2] [3, 3] [4, 5] [5, 8] [6, 13] [7, 21] [8, 34] [9, 55] ్தͷΛฦ͢ͷ͕͍͠ def fibonacci(n) a, b = 1, 1 n.times do |i| p [i, a] a, b = b, a + b end end fibonacci(10)
FiberͰॻ͖͢ API fib = Fiber.new do a, b = 1, 1 while true Fiber.yield(a) a, b = b, a + b end end 10.times do |n| p [n, fib.resume] end def fibonacci(n) a, b = 1, 1 n.times do |i| p [i, a] a, b = b, a + b end end fibonacci(10) FiberΛ͏ͱ్தܦաͷΛฦͤΔ
Fiber#resume Fiber fib = Fiber.new do a, b = 1, 1 while true Fiber.yield(a) a, b = b, a + b end end 10.times do |n| p [n, fib.resume] end FiberʹͳΓ͖ͬͯಈ͘
Fiber.yield resume Fiber resume fib = Fiber.new do a, b = 1, 1 while true Fiber.yield(a) a, b = b, a + b end end 10.times do |n| p [n, fib.resume] end resumeʹΔ
EnumeratorͰॻ͖͢ fib = Fiber.new do a, b = 1, 1 while true Fiber.yield(a) a, b = b, a + b end end 10.times do |n| p [n, fib.resume] end def fibonacci a, b = 1, 1 while true yield(a) a, b = b, a + b end end fib = to_enum(:fibonacci) 10.times do |n| p [n, fib.next] end
QueueΛհͨ͠ڠௐ Queue Thread Thread q = SizedQueue.new(1) Thread.new do 10.times do |n| sleep(rand) q.push(n) p [:push, n] end end Thread.new do 10.times do |n| sleep(rand) p [:pop, q.pop] end end.join
͜ΕͷFiber൛ Rdv Fiber rendez-vous rdv = Rdv.new Fiber.new do 10.times do |n| rdv.push(n) p [:push, n] end end.resume Fiber.new do 10.times do |n| p [:pop, rdv.pop] end end.resume
Rdvͷ࣮ initialize push pop def initialize @reader = [] @writer = [] end def push(it) if @reader.empty? @writer << [it, Fiber.current] return Fiber.yield end @reader.shift.resume(it) end def pop if @writer.empty? @reader << Fiber.current return Fiber.yield end value, fiber = @writer.shift fiber.resume return value end
initialize @reader pop @writer push Fiber def initialize @reader = [] @writer = [] end def push(it) if @reader.empty? @writer << [it, Fiber.current] return Fiber.yield end @reader.shift.resume(it) end def pop if @writer.empty? @reader << Fiber.current return Fiber.yield end value, fiber = @writer.shift fiber.resume return value end
push @reader (yield) @reader (resume) def initialize @reader = [] @writer = [] end def push(it) if @reader.empty? @writer << [it, Fiber.current] return Fiber.yield end @reader.shift.resume(it) end def pop if @writer.empty? @reader << Fiber.current return Fiber.yield end value, fiber = @writer.shift fiber.resume return value end
@reader͕͍ͳ͍ Fiber.current yield def initialize @reader = [] @writer = [] end def push(it) if @reader.empty? @writer << [it, Fiber.current] return Fiber.yield end @reader.shift.resume(it) end def pop if @writer.empty? @reader << Fiber.current return Fiber.yield end value, fiber = @writer.shift fiber.resume return value end
@reader͕͍Δ @reader resume pop Fiber def initialize @reader = [] @writer = [] end def push(it) if @reader.empty? @writer << [it, Fiber.current] return Fiber.yield end @reader.shift.resume(it) end def pop if @writer.empty? @reader << Fiber.current return Fiber.yield end value, fiber = @writer.shift fiber.resume return value end
pop @writer (yield) @writer (resume) def initialize @reader = [] @writer = [] end def push(it) if @reader.empty? @writer << [it, Fiber.current] return Fiber.yield end @reader.shift.resume(it) end def pop if @writer.empty? @reader << Fiber.current return Fiber.yield end value, fiber = @writer.shift fiber.resume return value end pushͱҰॹͩΑʂ Skip!
@writer͕͍ͳ͍ Fiber.current yield def initialize @reader = [] @writer = [] end def push(it) if @reader.empty? @writer << [it, Fiber.current] return Fiber.yield end @reader.shift.resume(it) end def pop if @writer.empty? @reader << Fiber.current return Fiber.yield end value, fiber = @writer.shift fiber.resume return value end Skip!
ݕࠪதͷഉଞ੍ޚ Fiber Thread def initialize @reader = [] @writer = [] end def push(it) if @reader.empty? @writer << [it, Fiber.current] return Fiber.yield end @reader.shift.resume(it) end def pop if @writer.empty? @reader << Fiber.current return Fiber.yield end value, fiber = @writer.shift fiber.resume return value end ThreadͷਓυΩυΩͯ͠Δͱࢥ͏
͏༷͘͝ࢠ rdv = Rdv.new Fiber.new do 10.times do |n| rdv.push(n) p [:push, n] end end.resume Fiber.new do 10.times do |n| p [:pop, rdv.pop] end end.resume Fiber.newした kara-matzを召喚
͏༷͘͝ࢠ rdv = Rdv.new Fiber.new do 10.times do |n| rdv.push(n) p [:push, n] end end.resume Fiber.new do 10.times do |n| p [:pop, rdv.pop] end end.resume kara-matzをresume kara-matzのターン
͏༷͘͝ࢠ rdv = Rdv.new Fiber.new do 10.times do |n| rdv.push(n) p [:push, n] end end.resume Fiber.new do 10.times do |n| p [:pop, rdv.pop] end end.resume kara-matzのpush! 相手がいない。 自分とデータをメモしyield。ターン終了
͏༷͘͝ࢠ rdv = Rdv.new Fiber.new do 10.times do |n| rdv.push(n) p [:push, n] end end.resume Fiber.new do 10.times do |n| p [:pop, rdv.pop] end end.resume メインのターン Fiber.new ichi-matzを召喚
͏༷͘͝ࢠ rdv = Rdv.new Fiber.new do 10.times do |n| rdv.push(n) p [:push, n] end end.resume Fiber.new do 10.times do |n| p [:pop, rdv.pop] end end.resume ichi-matzをresume ichi-matzのターン
͏༷͘͝ࢠ rdv = Rdv.new Fiber.new do 10.times do |n| rdv.push(n) p [:push, n] end end.resume Fiber.new do 10.times do |n| p [:pop, rdv.pop] end end.resume ichi-matzのpop! ichi-matzはメモを読んだ データを手にいれた。kara-matzをresumeしターン終了
͏༷͘͝ࢠ rdv = Rdv.new Fiber.new do 10.times do |n| rdv.push(n) p [:push, n] end end.resume Fiber.new do 10.times do |n| p [:pop, rdv.pop] end end.resume kara-matzのpush! 相手がいない。 自分とデータをメモしyield。ターン終了
͏༷͘͝ࢠ rdv = Rdv.new Fiber.new do 10.times do |n| rdv.push(n) p [:push, n] end end.resume Fiber.new do 10.times do |n| p [:pop, rdv.pop] end end.resume ichi-matzのpop! ichi-matzはメモを読んだ データを手にいれた。kara-matzをresumeしターン終了 Skip!
͏༷͘͝ࢠ rdv = Rdv.new Fiber.new do 10.times do |n| rdv.push(n) p [:push, n] end end.resume Fiber.new do 10.times do |n| p [:pop, rdv.pop] end end.resume ichi-matzはしんでしまった メインのターン メインはしんでしまった Skip!
ૉ͚ͩͲҰ్ I/O 1 def main_loop loop do select fds.each do |fd| call_callback end end end def on_accept c = accept loop do read_request(c) do_it write_response(c) end end def read_n(fd, sz) ... ... end
Thread൛ fd Thread def main_loop loop do select fds.each do |fd| call_callback end end end def on_accept c = accept Thread.new(c) do |fd| loop do read_request(fd) do_it write_response(fd) end end end def read_n(fd, sz) ... ... end Ճ͚ͩ͜͜ Ճ͚ͩ͜͜
Fiber൛ def main_loop loop do select fds.each do |fd| call_callback end end end def on_accept c = accept Fiber.new do loop do read_request(c) do_it write_response(c) end end.resume end def read_n(fd, sz) ... ... end Swapped with Fiber
Fiber൛վ I/O I/O def main_loop loop do select fds.each do |fd| call_callback end end end def on_accept c = accept Fiber.new do loop do read_request(c) do_it write_response(c) end end.resume end def read_n(fd, sz) ... fd.read_nonblock(sz) rescue WaitReadable Fiber.yield retry end
Block-ish non-block I/O Fiber.yield main_loop resume def main_loop loop do select fds.each do |fd| call_callback end end end def on_accept c = accept Fiber.new do loop do read_request(c) do_it write_response(c) end end.resume end def read_n(fd, sz) ... fd.read_nonblock(sz) rescue WaitReadable Fiber.yield retry end
Threadͱͷͪ߹Θͤ Thread.value IO.pipe close class ThreadTask def initialize(*args, &block) left, @right = IO.pipe @task = Thread.new do begin block.call(*args) ensure left.close end end end def value if @right Bartender.wait_readable(@right) @right.close end @task.value ensure @right = nil end end Skip!