Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Bartender / Xt Again

Bartender / Xt Again

オトナとRubyの資料でっす。
introduction of Bartender, a small framework for select, Fiber.

seki at druby.org

October 10, 2015
Tweet

More Decks by seki at druby.org

Other Decks in Programming

Transcript

  1. Bartender::Reader#read(n) def read(n) while @buf.bytesize < n chunk = _read(n)

    break if chunk.nil? || chunk.empty? @buf += chunk end @buf.slice!(0, n) end
  2. Bartender::Reader#_read(n) def _read(n) @fd.read_nonblock(n) rescue IO::WaitReadable select_readable retry end def

    select_readable @bartender[:read, @fd] = Fiber.current.method(:resume) Fiber.yield ensure @bartender.delete(:read, @fd) end 知らなかった!
  3. Bartender::Reader#_read(n) def _read(n) @fd.read_nonblock(n) rescue IO::WaitReadable select_readable retry end def

    select_readable @bartender[:read, @fd] = Fiber.current.method(:resume) Fiber.yield ensure @bartender.delete(:read, @fd) end イベントのコールバック を登録
  4. Bartender::Reader#_read(n) def _read(n) @fd.read_nonblock(n) rescue IO::WaitReadable select_readable retry end def

    select_readable @bartender[:read, @fd] = Fiber.current.method(:resume) Fiber.yield ensure @bartender.delete(:read, @fd) end Fiber.current ベンリ!
  5. Bartender::Reader#_read(n) def _read(n) @fd.read_nonblock(n) rescue IO::WaitReadable select_readable retry end def

    select_readable @bartender[:read, @fd] = Fiber.current.method(:resume) Fiber.yield ensure @bartender.delete(:read, @fd) end コールバックをはずす
  6. Bartender::Serverશจ class Server def initialize(bartender, port, &blk) @bartender = bartender

    @server = TCPServer.new(port) @bartender[:read, @server] = self.method(:on_accept) @blk = blk end def on_accept client = @server.accept reader = Reader.new(@bartender, client) writer = Writer.new(@bartender, client) fiber = Fiber.new do @blk.yield(reader, writer) end fiber.resume end end サーバーソケットをまつ Reader, Wrierをblockへ
  7. DRbEchoServerͷྫ def initialize(bartender, port) @rdv = Rdv.new Bartender::Server.new(bartender, port) do

    |reader, writer| begin while true _, msg, argv = req_drb(reader) case msg when 'push' value = @rdv.push(argv) else value = @rdv.pop end reply_drb(writer, true, value) end rescue p $! end end end
  8. DRbEchoServerͷྫ def load(reader, marshal=true) sz = reader.read(4) sz = sz.unpack('N')[0]

    data = reader.read(sz) return data unless marshal begin Marshal.load(data) rescue DRb::DRbUnknown.new($!, data) end end def req_drb(reader) ref = load(reader, false) msg = load(reader) argc = load(reader) argv = argc.times.collect { load(reader) } block = load(reader, false) [ref, msg, argv] end ブロックを気にせずreadし まくる
  9. Ұ੪௨஌ class Broadcast def initialize @reader = [] end def

    push(it) while not @reader.empty? @reader.shift.call(it) end end def pop @reader << Fiber.current.method(:resume) return Fiber.yield end end
  10. ଴ͪߦྻ def initialize @reader = [] @queue = [] end

    def push(it) @queue << it return if @reader.empty? @reader.shift.call(it) end def pop if @queue.empty? @reader << Fiber.current.method(:resume) return Fiber.yield end @queue.shift end
  11. ϥϯσϒʔ 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