Slide 1

Slide 1 text

Bartender Xt Again. ロールプレイングゲーム2 真打(仮) リメイク版ロールプレイングゲーム ルビーサファイア フレンドコード 2723-9375-2977 [email protected]

Slide 2

Slide 2 text

Pragmatic Bookshelf Author

Slide 3

Slide 3 text

͔͠͠ઈ൛

Slide 4

Slide 4 text

Xt 20ੈلͷX11ͷϑϨʔϜϫʔΫ I/Oଟݩ଴ͪ selectଐΛந৅Խ

Slide 5

Slide 5 text

ੈؒͰ͸ 1εϨουͷI/OଟॏԽ͕ྲྀߦ͍ͬͯΔΒ͍͠ εϨου͏Μͬͯ͜ݴ͑͹΢έΔ 21ੈل͍͢͝ʂ

Slide 6

Slide 6 text

ॳ࡮Γेप೥ dRuby ʹΑΔ ؔকढ़ஶ ෼ࢄ ɾ Web ϓϩάϥϛϯά

Slide 7

Slide 7 text

ॳ࡮Γेप೥ͷ൓ল ੈؒʹܴ߹͠ͳͯ͘͸ͳΒͳ͍ ઌߦ͗ͯ͢͠͸μϝ

Slide 8

Slide 8 text

#dRuby Φʔύʔπ @yugui https://twitter.com/yugui/status/439412852013551616

Slide 9

Slide 9 text

ܴ߹͠Α͏ XtͷهԱΛཔΓʹselectଐΛந৅Խͯ͠ΈΔ RubyͳͷͰFiber࢖͏͔ͳ

Slide 10

Slide 10 text

ΞʔςΟετͳͷͰ Node͸ݟͳ͍ Pythonͷ΋εϧʔ

Slide 11

Slide 11 text

Bartender selectΛগ͠ந৅Խ͢Δ FiberΛ࢖͏ ϞϊεϨουͰ͋Δ ଞͷselectଐ͸୭͔ʹͲ͏ʹ͔ͯ͠΋Β͏

Slide 12

Slide 12 text

Bartenderͷ༝དྷ όʔςϯμʔ TofuͰ΋࢖໊ͬͨલ Think Class Library͔ΒύΫͬͨ

Slide 13

Slide 13 text

Bartender::App App#[]=(event, fd, callback) ίʔϧόοΫͷొ࿥ɻ Ϣʔβʔσʔλ͸ͳ͠ɻ⇦ MethodΦϒδΣΫτΛ౉ͤ͹͍͍͡ΌΜ App#delete(event, fd) App#run ϝΠϯϧʔϓ

Slide 14

Slide 14 text

͜Ε͚ͩ [event, fd]ͱϝιουΛ݁ͼ͚ͭΔ͚ͩ

Slide 15

Slide 15 text

ReaderͱWriterɺServer ͜ΕͰ͸ෆศͳͷͰϢʔςΟϦςΟʔΛ wellksײ non-block I/OΛblock෩ʹ͢Δ blockͦ͠͏ʹͳͬͨΒ࣮ߦݖΛख์͢ Fiber.yieldͶ αʔόʔιέοτ༻ͷϢʔςΟϦςΟʔ΋!

Slide 16

Slide 16 text

Bartender::Reader Reader#read(n) nΦΫςοτಡΉ Reader#read_until(sep="\r\n", chunk_size=8192) Reader#readln ηύʔϨλ·Ͱʢߦ຤·ͰʣಡΜͰฦ͢

Slide 17

Slide 17 text

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

Slide 18

Slide 18 text

readͷ಺ଆͷ_read͕ϛι Θ͔Γʹ͍͚͘Ͳ͕͜͜Πέϝϯ

Slide 19

Slide 19 text

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 知らなかった!

Slide 20

Slide 20 text

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 イベントのコールバック を登録

Slide 21

Slide 21 text

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 ベンリ!

Slide 22

Slide 22 text

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 コールバックをはずす

Slide 23

Slide 23 text

dRubyϓϩτίϧ ࣮ݧ༻ΫϥΠΞϯτॻ͘ͷ͕໘౗ dRubyͷϓϩτίϧΛ࿩ͤΔαʔόΛॻ͜͏ ...

Slide 24

Slide 24 text

dRubyϓϩτίϧ ಈ͍ͨʂ͕͢͞ࢲʂ

Slide 25

Slide 25 text

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へ

Slide 26

Slide 26 text

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

Slide 27

Slide 27 text

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し まくる

Slide 28

Slide 28 text

Fiber׳Ε͖ͯͨ Fiberͷ௨৴ϓϦϛςΟϒ࡞ΕΔ͔΋ Threadͷ௨৴ϓϦϛςΟϒͱ͸૬ੑѱ͍ Queueͱ͔࢖ͬͨΒݻ·ͬͪΌ͏Αʂ

Slide 29

Slide 29 text

Ұ੪௨஌ 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

Slide 30

Slide 30 text

଴ͪߦྻ 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

Slide 31

Slide 31 text

ϥϯσϒʔ 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

Slide 32

Slide 32 text

هԱͷதͷXtΛ࠶ݱͨ͠ େੲͷωλ͸਎ମ͕֮͑ͯΔ selectͷϑϨʔϜϫʔΫ͸୯७͕ͩΞϓϦ͕ ೉͍͠ͷͰ࣮ݧͯ͠Έͨ dRubyͳΒ࣮ݧΫϥΠΞϯτ࡞ΒͣʹࡁΉ dRubyͷશͯͷຐ๏Λ࣮૷͢Δͷ͸FiberͰ͸ ࠔ೉Ͱ͋Δ Fiber࢖͏ΑΓThreadͷํ͕͍͍Α