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

Make your own synchronization mechanism.

Make your own synchronization mechanism.

RubyKaigi2014

40f4d1f2e77078955bd01e9fb4a503ba?s=128

seki at druby.org

September 20, 2014
Tweet

Transcript

  1. Make your own synchronization mechanism. ಉظϝΧΛϙνοͱͳɻ seki@ruby-lang.org

  2. slide sponsors !LPV ؙٔ،؝٦سծ荈歋ח⢪ִ׷اؿزؐؑ،׾Ꟛ涪ׅ׷➂׾⹫꧊ չؙٔ،؝٦سػحث䱰欽պד嗚稊 !NBNF ְַ׃׋خ؎٦زח鸨ְ׋ְז׵չהגַպח꧊ת׶ת׃׳ ֲ 㹋遤㨻㆞ꞿ⤘״׶ 

    !KVOF ꟼׁ׿ךز٦ؙכծ䞸׸ׇׁせ鎉׌ה䙼׏ג耮ֻהׁ׵ח嚂׃׭ ׷״ֲחז׶תׅ !UTVCPJ3VCZ,BJHJח遤ֽזְךדծ✮皾׾ֿ׍׵ח䫎♴׃תׅկ״ְ涪邌 ׾կ !1613-׮⿫⸇ׅ׷הגַדכծׁ׵ז׷⿫⸇罏׾ֶת׍׃גְתׅկ !IJSBZBTVؿؑ؎ز׍ׯ׿ַ׻ְְ״IUUQXXXGBUFNPF !PHJKVO֮הד剅ֻ !ZBODZB!IJTBTIJN!WFTUJHF@!OPQMBOT!USBDL
  3. sticker sponsors

  4. T-shirts sponsors TV[VSJKQN@TFLJ

  5. RubyHiroba toRuby and guRuby Tochigi/Gunma Ruby meetup 2014-9-21 9:30

  6. ͱͪ͗ςετͷձٞ03 2014−10−4 Ӊ౎ٶେֶ #toteka

  7. no commit is good commit ERB/dRuby/Rinda

  8. Buy!!! dRuby ʹΑΔ ؔকढ़ஶ ෼ࢄ ɾ Web ϓϩάϥϛϯά

  9. Goͷਓؾ͕ౄ·͍͠ Goνϟωϧ͕͍͢͝ਓؾʂ RubyͷQueueΈ͍ͨͳͷ͕͙͢࢖͑Δ ͜Ε͸ένΛ͚ͭͳͯ͘͸ͳΒͳ͍

  10. ࠓ೔͓࿩͢Δ͜ͱ Rubyͷ͓·͚ͷಉظͷ࢓૊Έͷ͓͞Β͍ Go෩νϟωϧͷ࡞੒Λ௨ͯ͡ಘΒΕͨૉ੖ Β͍͠஌ݟ ։ൃ೔هΛݩʹ਺λʔϯͰ

  11. খ͍͞ࠒʹಡΜͩຊ

  12. MINIXຊ ͍ΖΜͳಉظͷ࿩͕ग़ͯ͘Δ ಉظϝΧχζϜ͕ͳʹ͔Ұͭ͋Δͱɺଞͷछ ྨͷಉظϝΧχζϜ͕࣮૷Ͱ͖Δ

  13. ಌΕ ੈքͷ࢓૊Έͷߏங ੈքͷجૅͱͳΔҰ൪খ͞ͳػೳ ਥೋ ԶͷಉظϝΧ

  14. Rubyʹ͍ͭͯΔಉظϝΧ ଴ͪ߹Θͤͦͷ΋ͷ ଴ͪ߹Θͤͱ৘ใͷަ׵

  15. ଴߹ͤͷͨΊͷಉظϝΧ Monitorྨ Mutex MonitorMixin

  16. ಉظϝΧͷ஫ҙ ަࠩ఺ͷ৴߸ػ ΈΜͳ͕कΔͱ͏·͍͘͘ कΒͳ͍ͱࣄނ͕͓͖Δ͜ͱ͕͋Δ ͓͖ͳ͍͜ͱ΋͋Δ ࣄނ͕͓͖ͳ͔͔ͬͨΒͱݴͬͯਖ਼͍͠ ͱ͸ݶΒͳ͍

  17. ৘ใͷަ׵΋͢ΔಉظϝΧ Queue΍TupleSpace socket, pipe ৘ใΛަ׵͢Δ ަ׵ͷ͍ͭͰʹ଴ͪ߹ΘͤΔ

  18. Queue pushͱpop ۭͷͱ͖ʹpop͢Δͱpush͞ΕΔ·Ͱࢭ·Δ ʢෳ਺ͷpop͕ಉ࣌͋Δͱ͖΋͏·͘΍Δʣ

  19. SizedQueue pushͱpop ۭͷͱ͖ʹpop͢Δͱpush͞ΕΔ·Ͱࢭ·Δ ʢෳ਺ͷpop͕ಉ࣌͋Δͱ͖΋͏·͘΍Δʣ ༰ྔΛӽ͑ͯpush͢Δͱۭ͘·Ͱࢭ·Δ

  20. ґଘؔ܎ͱ଴ͪ߹Θͤ σʔλͷґଘؔ܎Λϓϩάϥϛϯά͢Δ͜ͱ Ͱฒߦॲཧ͕ॻ͚ͯ޷͖ʢࢲ͕ʣ ୯ͳΔ଴߹ͤΑΓ΋ϛε͠ʹ͍͘ʢࢲ͕ʣ

  21. Goͷνϟωϧ εϨουؒʢͪΐͬͱӕʣͰ৘ใΛަ׵ ૹ৴ૢ࡞ͱड৴ૢ࡞ʢ<-ʣ chan <- obj it = <- chan

    ༰ྔʹ੍ݶ͕͋Δ SizedQueueʹࣅͯΔΑ͏ͳ...
  22. ηϧϑϞνϕʔτ Α͘ௐ΂ͳ͍Ͱ࡞Δ΂͖ ௐ΂Δͱߴ͗͢Δϋʔυϧʹؾ͍ͮͯ͠·͏

  23. ph.1 SizedQueue ୯ʹSizedQueueͰαϯϓϧΛॻ͖׵͑ ԋࢉࢠΊΜͲ͍͘͞ͷͰwrite, readʹͨ͠ ܕ΋ཁΒͳ͍

  24. SizedQueueͦͷ΋ͷ def initialize(size) @writing = SizedQueue.new(size) end def read @writing.pop

    end def write(value) @writing.push(value) end
  25. SizedQueue͡Όͳ͔ͬͨ 㱺 ͳΜ͔ҧ͏͜ͱʹؾ͍ͮͨ େ͖͕͞0ͷνϟωϧ ૹ৴ऀͱड৴ऀ͕ἧ͏·Ͱ଴߹ͤ େ͖͕͞1Ҏ্ͷͱ͖͸SizedQueueͱಉ͡ ࢓༷ΛΑ͘ௐ΂ͨ΄͏͕͍͍

  26. ph.2 ࣗ෼ͰٳΉ࡞ઓ size͕0ͷͱ͖ͷڍಈΛಛผʹ͢Δ writer͸pushͷ͋ͱsleep͢Δ reader͸popͷ͋ͱwakeup͢Δ

  27. ph.2 ࣗ෼ͰٳΉ࡞ઓ def initialize(size=0) @size = size if size ==

    0 @writing = SizedQueue.new(1) else @writing = SizedQueue.new(size) end end def read return @writing.pop if @size > 0 value, writer = @writing.pop return value ensure writer.wakeup if @size == 0 end def write(value) return @writing.push(value) if @size > 0 @writing.push([value, Thread.current]) sleep end 5ISFBE׾床׃ג 饯ֿ׃ג׮׵ֲ 5ISFBE׾床׃ג 饯ֿ׃ג׮׵ֲ
  28. wakeupͷ͋ͱʹsleep... def initialize(size=0) @size = size if size == 0

    @writing = SizedQueue.new(1) else @writing = SizedQueue.new(size) end end def read return @writing.pop if @size > 0 value, writer = @writing.pop return value ensure writer.wakeup if @size == 0 end def write(value) return @writing.push(value) if @size > 0 @writing.push([value, Thread.current]) sleep end ر٦ة ꟦麩ְ
  29. ͍·ͷ͸μϝͳྫ ࣗ෼Ͱsleepͱ͔͍͍ͨͯؒҧͬͯΔʢͷΛ ࢥ͍ग़ͨ͠ʣ Rubyʹ͍ͭͯΔ෦඼Λ࢖͏΄͏͕ྑ͍

  30. ph.3 Χ΢ϯςΟϯάηϚϑΥ ࠷ॳ͔Βͦ͏͠Ζ ·͡Ίʹॻ͘ͷΊΜͲ͏ͳͷͰQueueͰ୅༻

  31. όοϑΝΛ਺͑Δ܎ def initialize(size) @reading = Queue.new @writing = Queue.new size.times

    { @reading.push(true) } end def read @reading.push(true) @writing.pop end def write(value) @reading.pop @writing.push(value) end ر٦ة
  32. QueueͰηϚϑΥ def initialize(size) @reading = Queue.new @writing = Queue.new size.times

    { @reading.push(true) } end def read @reading.push(true) @writing.pop end def write(value) @reading.pop @writing.push(value) end ず劍欽 ず劍欽 إوؿؓ
  33. όοϑΝ෼up͠ͱ͘ def initialize(size) @reading = Queue.new @writing = Queue.new size.times

    { @reading.push(true) } end def read @reading.push(true) @writing.pop end def write(value) @reading.pop @writing.push(value) end غحؿ؋ⴓ
  34. ׬੒ͨ͠ͱࢥͬͨ Queue͸୯७ͰԠ༻΋؆୯ ಉظϝΧ࡞Γ΍͍͢ ͕ɺ΋͏ͪΐͬͱௐ΂ͨΒselect͕͋ͬͨ...

  35. select Goνϟωϧʹ͸select͕͋ΔΒ͍͠ ଟݩ଴ͪ ෳ਺ͷνϟωϧʹ͍ͭͯɺಡΜͰ΋ϒϩοΫ ͠ͳ͍νϟωϧΛฦ͢

  36. selectΊΜͲ͍͘͞ ෳ਺ͷνϟωϧͷ͏ͪɺͲΕ͔Ұ͕ͭ readableʹͳΔ·ͰͷϒϩοΫ Queue#pop͸ϒϩοΫͪ͠Ό͏

  37. ෳ਺QueueͰselect ෳ਺ͷQueueΛ·ͱΊΔQueue࡞ઓ νϟωϧͷ਺͚ͩεϨουඞཁ popͰ͖ͨͱ͖ʹ͸ཁૉΛফඅͯ͠Δ selectͱ͍͏͔Βʹ͸ফඅ͠ͳ͍ํ͕Ϟς ಉ͡ޮՌͷΞϓϦέʔγϣϯ͸ॻ͚Δ͚Ͳಉ ͡ΠϯλʔϑΣΠε೉͍͠

  38. ΍ͬͺΓ Queueϕʔεͷ࡞ઓ͸μϝͳͷͰ͸...

  39. Wait a moment ✓ +12:00ɹ ✓ Queueܥྻ͸ศར ✓ selectҎ֎͸؆୯ʹ࡞Εͦ͏ ✓

    ࣍͸select΋Մೳͳ࣮૷
  40. ph.4 TupleSpace࢖͏ ζϧ write, take, read takeͱreadʹ͸ύλʔϯ͕ࢦఆͰ͖Δ === ෳࡶͳঢ়ଶΛ͍͍ͩͨ଴ͯΔ readableͳνϟωϧΛಡΉʗ଴ͭ

    ͙͢Ͱ͖ͦ͏
  41. ࢖͍ํ͔Βઃܭ͢Δ chan1 = ChannelSpace.open(1) chan1.write('hello') p chan1.read chan2 = ChannelSpace.open(0)

    timeout = ChannelSpace.after(10) readable = ChannelSpace.select([chan1, chan2, timeout]) p readable.read
  42. openͰੜ੒ chan1 = ChannelSpace.open(1) chan1.write('hello') p chan1.read chan2 = ChannelSpace.open(0)

    timeout = ChannelSpace.after(10) readable = ChannelSpace.select([chan1, chan2, timeout]) p readable.read إوؿؓ PQFO )BOEMF
  43. write/read chan1 = ChannelSpace.open(1) chan1.write('hello') p chan1.read chan2 = ChannelSpace.open(0)

    timeout = ChannelSpace.after(10) readable = ChannelSpace.select([chan1, chan2, timeout]) p readable.read XSJUF SFBE
  44. nඵޙʹͳʹ͔ૹΔνϟωϧ chan1 = ChannelSpace.open(1) chan1.write('hello') p chan1.read chan2 = ChannelSpace.open(0)

    timeout = ChannelSpace.after(10) readable = ChannelSpace.select([chan1, chan2, timeout]) p readable.read TFD
  45. readableΛฦ͢ chan1 = ChannelSpace.open(1) chan1.write('hello') p chan1.read chan2 = ChannelSpace.open(0)

    timeout = ChannelSpace.after(10) readable = ChannelSpace.select([chan1, chan2, timeout]) p readable.read BSSBZ ׉ך䖓 SFBE
  46. Ͱ͖ͨ # -*- coding: utf-8 -*- require 'rinda/tuplespace' class ChannelSpace

    include DRbUndumped class ChannelError < RuntimeError def initialize(str, handle) @channel = handle super(str) end attr_reader :channel end class Readable def ===(it) it.readable? end end class Any def initialize(ary) @ary = ary end def ===(it) @ary.include?(it) end end class Channel def initialize(ts, size, handle) @ts = ts @handle = handle @reader = [] @writer = [] @buf = [] @size = size @closed = false end def readable? _readable? || @closed end def _readable? @buf.size + @writer.size > 0 end def close @closed = true while writer = @writer.shift @ts.write([:write, @handle, writer[1], self]) end while reader = @reader.shift @ts.write([:read, @handle, reader, self]) end end def writer_shift return if @writer.empty? value, key = @writer.shift @buf << value @ts.write([:write, @handle, key, value]) end def buf_push(value) @writer << [value, Thread.current] if @buf.size < @size writer_shift end end def buf_shift writer_shift @buf.shift end def req_read if _readable? @ts.write([:read, @handle, Thread.current, buf_shift]) else raise ChannelError.new('closed channel.', @handle) if @closed @reader << Thread.current end end def req_write(value) raise ChannelError.new('closed channel.', @handle) if @closed buf_push(value) return if @reader.empty? @ts.write([:read, @handle, @reader.shift, buf_shift]) end end class Handle include DRbUndumped def initialize(cs) @cs = cs end def write(value) @cs.write(self, value) end def read @cs.read(self) end def close @cs.close(self) end end def initialize @ts = Rinda::TupleSpace.new @readable = Readable.new end def open(size=0) handle = Handle.new(self) @ts.write([handle, Channel.new(@ts, size, handle)]) handle end def close(handle) begin _, chan = @ts.take([handle, nil]) chan.close ensure @ts.write([handle, chan]) end end def write(handle, value) begin _, chan = @ts.take([handle, nil]) chan.req_write(value) ensure @ts.write([handle, chan]) end _, _, _, value = @ts.take([:write, handle, Thread.current, nil]) raise ChannelError.new('closed channel.', handle) if value == chan value end def read(handle) begin _, chan = @ts.take([handle, nil]) chan.req_read ensure @ts.write([handle, chan]) end _, _, _, value = @ts.take([:read, handle, Thread.current, nil]) raise ChannelError.new('closed channel.', handle) if value == chan value end def select(set) handle, _ = @ts.read([Any.new(set), @readable]) handle end def select_and_read(set) begin handle, chan = @ts.take([Any.new(set), @readable]) chan.req_read ensure @ts.write([handle, chan]) end _, _, _, value = @ts.take([:read, handle, Thread.current, nil]) raise ChannelError.new('closed channel.', handle) if value == chan return handle, value end def after(sec, value=nil) chan = open Thread.new {sleep sec; chan.write(value)} chan end @cs = self.new def self.open(size=0) @cs.open(size) end def self.after(sec, value=nil) @cs.after(sec, value) end def self.select(set) @cs.select(set) end def self.select_and_read(set) @cs.select_and_read(set) end end
  47. TupleSpaceʹӅ͢ $IBOOFM4QBDF 5VQMF4QBDF $IBOOFM $IBOOFM $IBOOFM )BOEMF )BOEMF )BOEMF )BOEMF

    銲稆ךUVQMF
  48. ର৅ʹ஫໨ͨ͠ഉଞ੍ޚ def write(handle, value) begin _, chan = @ts.take([handle, nil])

    chan.req_write(value) ensure @ts.write([handle, chan]) end _, _, _, value = @ts.take([:write, handle, Thread.current, nil]) raise ChannelError.new('closed channel.', handle) if value == chan value end def read(handle) begin _, chan = @ts.take([handle, nil]) chan.req_read ensure @ts.write([handle, chan]) end _, _, _, value = @ts.take([:read, handle, Thread.current, nil]) raise ChannelError.new('closed channel.', handle) if value == chan value end UBLF XSJUF UBLF XSJUF UBLF XSJUF UBLF XSJUF 㥨ֹז 乼⡲
  49. Actor෩௨৴ def write(handle, value) begin _, chan = @ts.take([handle, nil])

    chan.req_write(value) ensure @ts.write([handle, chan]) end _, _, _, value = @ts.take([:write, handle, Thread.current, nil]) raise ChannelError.new('closed channel.', handle) if value == chan value end def read(handle) begin _, chan = @ts.take([handle, nil]) chan.req_read ensure @ts.write([handle, chan]) end _, _, _, value = @ts.take([:read, handle, Thread.current, nil]) raise ChannelError.new('closed channel.', handle) if value == chan value end SFRVFTU SFR SFT SFT GSPN IBOEMF WBMVF LJOE
  50. selectͷ࣮૷ def select(set) handle, _ = @ts.read([Any.new(set), @readable]) handle end

    ... class Readable def ===(it) it.readable? end end class Any def initialize(ary) @ary = ary end def ===(it) @ary.include?(it) end end  DIBOOFM IBOEMF DIBOOFM IBOEMF DIBOOFM IBOEMF 
  51. selectͷ࣮૷ def select(set) handle, _ = @ts.read([Any.new(set), @readable]) handle end

    ... class Readable def ===(it) it.readable? end end class Any def initialize(ary) @ary = ary end def ===(it) @ary.include?(it) end end  DIBOOFM IBOEMF DIBOOFM IBOEMF DIBOOFM IBOEMF ػة٦ٝ UTSFBE
  52. ph.5 MonitorͰॻ͖௚͢ ΍ͬͯͳ͍

  53. ph.6 ֦ுϥΠϒϥϦԽ ΋ͪΖΜ΍ͬͯͳ͍

  54. ·ͱΊ Goνϟωϧ෩ಉظϝΧΛॻ͖ͳ͕Βɺ։ൃ ͷ༷ࢠͱςΫχοΫͷҰ෦Λࣔͨ͠ ಉظϝΧ͸ಉظϝΧͰॻ͚ΔͷͰ͍͍ͪͪͼͬ ͘Γ͠ͳ͍ TupleSpace͸ಉظϝΧͷϓϩτλΠϓʹྑ͍ ͷͰຊΛങ͓͏

  55. ·ͱΊ ΞϓϦέʔγϣϯͷϢʔεέʔεͷࢹ఺Ͱߟ ͑Δͱ΋ͬͱྑ͍౴͕͑͋Δʢͷ͸࿩͞ͳ͔ͬ ͨʣ