Rubyã®ã¹ã¬ããã¯ç´ æ´ãããã¨æãã®ã§ããããªãã人æ°ãããã¾ããã
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
Enumeratorãªã©ã®å®è£
ããããªæãã§ã§ãã¦ããã§ããããã
äºã¤ã®å®è¡ä¸»ä½ï¼fibã®Fiberã¨10.times..ãã¦ãã¡ã¤ã³é¨åï¼ã¯ã¡ã¤ã³é¨åãFiberãå©ç¨ãã¦ãããããªæ§å³ã§ãï¼ï¼ï¼ï¼ã
resumeããã¹ãç¸æã®ãã¨ãç¥ã£ã¦ããããããFiberãè³æºã¿ãããªæãï¼ï¼ï¼ï¼ï¼ã
ãã«ãã¹ã¬ããã§ã®ããã°ã©ãã³ã°ã®ããã«ãè¤æ°ã®Fiberéã§é£æºããé°å²æ°ã®ã³ã¼ããæ¸ãã«ã¯ã©ããããããã§ãããã
ã¹ã¬ããã§ããã¨æ¬¡ã®ãããªQueueãä»ãã¦åæãããããªãã®ã§ãã
require '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
ã¹ã¬ããéã¯Queueã ãã®ä»ãåãã§ãç¸æã®å®è¡ä¸»ä½ï¼ãã®å ´åã¯Threadï¼ã«ã¤ãã¦ã¯èå³ãããã¾ããã
ãã£ãããï¼
ãããã£ãåææ©æ§ãFiberã§æ¸ãã«ã¯ã©ãããããããã§ãããã
ããªããã£ãèªä½ãFiberã§ç®¡çãããã¨ããããã試è¡é¯èª¤ãããã ãã©ããã¾ãããã¾ããã§ãããï¼ãã¿ã¯ã½ï¼
require 'fiber'ããã¨ä½¿ç¨ã§ãããFiber.currentãè¦ã¤ãã¦ããã¯ç°¡åã«è¨è¿°ã§ãããã¨ããããã¾ããã
åæããªããã£ããå©ç¨ããå®è¡ä¸»ä½ãã¡ã¢ãã¦yield, resumeã§ããã®ã§ãäºåã«é¢ä¿è
ï¼é¢ä¿ããFiberï¼ãç¥ãåã£ã¦ããå¿
è¦ãããã¾ããã*1
次ã®ä¾ã¯pushãããFiberã¨popãããFiberãæã£ããããªãã¸ã§ã¯ããä¸ã¤pushå´ããpopå´ã¸æ¸¡ãã¦ã両è ãåéãããåææ©æ§ï¼ã©ã³ããã¼ï¼ã§ãã
require 'fiber' class Rdv def initialize @reader = [] @queue = [] end def push(it) if @reader.empty? @queue << [it, Fiber.current.method(:resume)] return Fiber.yield end @reader.shift.call(it) end def pop if @queue.empty? @reader << Fiber.current.method(:resume) return Fiber.yield end value, fiber = @queue.shift fiber.call return value end end if __FILE__ == $0 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 end
ä¸è¬çãªåææ©æ§ãä½ãã¤ãã£ãªã ã¯æ¬¡ã®ããã«ãªãã¾ãã
- å¼ã³åºããFIberãã¡ã¢
- Fiber.yield
- åéããããã¡ã¢ãã¦ãããFiberã«resume
1ã®åããããã¯ã3ã®åã«å®äºæ¡ä»¶ããã§ãã¯ããã¨æãã¾ãã
pushã®å ´åã¯ããããæå³ã§ãã
- å¾ ã£ã¦ãã人ï¼popå´ï¼ãããªããªããFiberãã¡ã¢ãã¦yieldããã®ã¨ãä¸ç·ã«æ¸¡ããããªãã¸ã§ã¯ããã¡ã¢ãã¾ãã
- å¾ ã£ã¦ãã人ãããå ´åãã¾ãã¯åéãããã¨ããä¸ã¤åãåºãã¦resume
popå´ã¯ããããæ°æã¡ã§ãã
- ãã¼ã¿ããªããªãï¼pushå´ãããªããªãï¼ãFiberãã¡ã¢ãã¦yield
- ãã¼ã¿ãããå ´åãã¾ãã¯åéãããã¨ããä¸ã¤åãåºãã¦resumeããã®ã¨ãä¸ç·ã«ã¡ã¢ãããªãã¸ã§ã¯ãã渡ãã¾ãã
Threadã®ã¨ãã¨éãã®ã¯ãæ¡ä»¶ãæ¤æ»ããéãããã¯ããå¿ è¦ããªãã¨ããã§ããThreadã®å ´åã¯ãå¾ ã£ã¦ã人ãå ¨å¡ãä¸æã«åéãã¦ãããã¯ãç²å¾ã§ããå®è¡ä¸»ä½ã ããå ã«é²ã¿ã¾ãããFiberã§ã¯åæã«ä¸ã¤ããåããªãã®ãããã£ã¦ããã®ã§ããããã£ã管çã¯å¿ è¦ããã¾ããããããããããã©ãFiberã§æ¸ãã¨ãã®ãã¢ã¯ãããããã¨ãThreadè³ã§ãããã¯ãã°ããã¨æãé¨åããFiberã§ã¯é¢ä¿ãªãã£ããã¨æ¼ã殺ãã¨ããããããã¾ããã
Bartender
https://github.com/seki/bartender
Bartenderã¨ããselectãæ½è±¡åããã©ã¤ãã©ãªãæ¸ãã¦ãã¾ããããã¯çªãè©°ããã¨fdã¨readable, writableã®çµã¿ã«ä¸ã¤ã ãã³ã¼ã«ããã¯ãè¨å®ã§ããã ãã®ã©ã¤ãã©ãªã§ãã
ããããFiberã¨çµã¿åããã¦ãFiber.current.method(:resume)ãã³ã¼ã«ããã¯ã¨ãã¦ç»é²ãããã¨ã§é¢ç½ããã®ãããããã³ã°ã®read/write風ã«ã¢ããªã±ã¼ã·ã§ã³ãæ¸ãã¨ããããã¯ããããªã¨ãã¯ä»ã®Fiberã«å®è¡æ¨©ã渡ããããã¯ããªããããããã³ã°é¢¨ãã³ããããã³ã°IOãå®ç¾ã§ãã¾ãã
def wait_io(event, fd) self[event, fd] = Fiber.current.method(:resume) Fiber.yield ensure delete(event, fd) end def wait_readable(fd); wait_io(:read, fd); end def _read(fd, sz) return fd.read_nonblock(sz) rescue IO::WaitReadable wait_readable(fd) retry end
readå¨ãã®å®è£ ãæãåºãã¨ãããªãã¾ããï¼SSLã ã¨readã§ãWaitWritableãæ¥ããããªã®ã§å¯¾å¿ããªãã¨ï¼
ã¢ããªã±ã¼ã·ã§ã³ã®å®éã¯ã¾ããã¨ã§ã
*1:ãã®ä¾ã§ã¯Fiber.current.method(:resume)ãè¦ãã¦ãã¾ãããåã«Fiber.currentã§ã大ä¸å¤«ã