Upgrade to PRO for Only $50/Year—Limited-Time Offer! 🔥

らくらくRactor

 らくらくRactor

Fukuoka.rb 200回 LT大会 (#202)
https://fukuokarb.connpass.com/event/206956/

発表後にご指摘を頂き、22ページでMutex.newを行なっていた箇所をサンプルコードにて修正しました。
https://github.com/shioimm/til/blob/57b268151751f7f97bbc08c002d81e74fddd6732/activities/20210324_fukuoka_200/producer_consumer/thread.rb#L39

More Decks by Misaki Shioi(塩井美咲/しおい)

Other Decks in Programming

Transcript

  1. 5ISFBEΛ࢖͏ϓϩάϥϜͷશମ૾ class Producer # … class Consumer # … class

    Numbering # … class Channel # … channel = Channel.new(3) producers = 3.times.map { Thread.new { # … } } consumers = 3.times.map { Thread.new { # … } } producers.each(&:join) consumers.each(&:join) $IBOOFMΫϥε ࠾൪ػΫϥε 1SPEVDFSΫϥε $POTVNFSΫϥε ϝΠϯϓϩάϥϜ
  2. ϝΠϯϓϩάϥϜͷ࣮૷ channel = Channel.new(3) producers = 3.times.map { |i| Thread.new

    do Producer.new(“P-#{i + 1}”, channel).run end } consumers = 3.times.map { |i| Thread.new do Consumer.new(“C-#{i + 1}”, channel).run end } producers.each(&:join) consumers.each(&:join) QSPEVDUΛͭϓʔϧ͢Δ$IBOOFMΛੜ੒ ͭͷεϨουͰ 1SPEVDFSΦϒδΣΫτΛ ੜ੒͠ɺՔಇͤ͞Δ ͭͷεϨουͰ $POTVNFSΦϒδΣΫτΛ ੜ੒͠ɺՔಇͤ͞Δ
  3. ϝΠϯϓϩάϥϜͷ࣮૷ channel = Channel.new(3) producers = 3.times.map { |i| Thread.new

    do Producer.new(“P-#{i + 1}”, channel).run end } consumers = 3.times.map { |i| Thread.new do Consumer.new(“C-#{i + 1}”, channel).run end } producers.each(&:join) consumers.each(&:join) Ҿ਺ͱ֤ͯ͠εϨουͷ໊લͱ $IBOOFMΛ౉͢ ֤εϨουͷ࣮ߦΛ଴ͪ߹ΘͤΔ
  4. 1SPEVDFSΫϥεͷ࣮૷ class Producer def initialize(name, channel) Thread.current.name = name @channel

    = channel end def run loop do product_no = Numbering.issue @channel.put "Product no. #{product_no}" end end end ࠾൪ػ͔Β QSPEVDU൪߸Λऔಘ͢Δ ࠾൪ͨ͠QSPEVDUΛ$IBOOFMʹஔ͘ # εϨουͷ໊લΛอଘ # ChannelΦϒδΣΫτ
  5. ࠾൪ػΫϥεͷ࣮૷ class Numbering @@product_no = 0 def self.issue Mutex.new.synchronize do

    @@product_no += 1 end end end QSPEVDU൪߸ΛΧ΢ϯτΞοϓ͠ɺฦ͢ .VUFYTZODISPOJ[F ಉ࣌ʹΞΫηεͰ͖ΔͷΛ εϨουʹ੍ݶ͢Δ͜ͱͰ ةݥྖҬΛอޢ͢Δ ෳ਺ͷ1SPEVDFSεϨου͔Β ಉ࣌ʹΞΫηε͞ΕΔͨΊ ڝ߹͠ͳ͍Α͏ϩοΫΛ͔͚Δ
  6. $IBOOFMΫϥεͷ࣮૷ class Channel def initialize(size) @products = [] @size =

    size @mutex = Mutex.new @cond = ConditionVariable.new end def put(product) # … end def take # … end end 1SPEVDFSΦϒδΣΫτͷதͰݺ͹ΕΔϝιου QSPEVDUΛϓʔϧʹೖΕΔͨΊͷ΋ͷ $POTVNFSΦϒδΣΫτͷதͰݺ͹ΕΔϝιου QSPEVDUΛϓʔϧ͔ΒऔΓग़ͨ͢Ίͷ΋ͷ # mutex # ৚݅ม਺ # Channelͷϓʔϧ # Channel͕ಉ࣌ʹϓʔϧͰ͖Δ࠷େ਺
  7. $IBOOFMΫϥεͷ࣮૷ QVUϝιου class Channel def initialize(size) # … def put(product)

    @mutex.synchronize do while @products.size >= @size @cond.wait(@mutex) end # … end end def take # … end $POEJUJPO7BSJBCMFXBJU ৚͕݅ຬͨ͞ΕΔ·Ͱ NVUFYͷϩοΫΛղআ͠ɺ ॲཧΛ଴ػͤ͞Δ ϓʔϧʹۭ͖͕ͳ͍৔߹ɺ QSPEVDUΛϓʔϧʹೖΕΔ ͜ͱ͕Ͱ͖ͳ͍
  8. $IBOOFMΫϥεͷ࣮૷ QVUϝιου class Channel def initialize(size) # … def put(product)

    @mutex.synchronize do while @products.size >= @size @cond.wait(@mutex) end # … end end def take # … end ϓʔϧʹۭ͖͕ͳ͍৔߹ɺ QSPEVDUΛϓʔϧʹೖΕΔ ͜ͱ͕Ͱ͖ͳ͍ ‎৚݅ม਺Λ࢖ͬͯ ϓʔϧʹۭ͖͕Ͱ͖Δ·Ͱ ͜͜ͰॲཧΛ଴ػ͢Δ $POEJUJPO7BSJBCMFXBJU ৚͕݅ຬͨ͞ΕΔ·Ͱ NVUFYͷϩοΫΛղআ͠ɺ ॲཧΛ଴ػͤ͞Δ
  9. $IBOOFMΫϥεͷ࣮૷ QVUϝιου class Channel def initialize(size) # … def put(product)

    @mutex.synchronize do while @products.size >= @size @cond.wait(@mutex) end # … end end def take # … end ϓʔϧʹۭ͖͕Ͱ͖Δͷ͸ ͍ͭʁ
  10. class Channel def initialize(size) # … def put(product) # …

    def take @mutex.synchronize do # … product = @products.pop @cond.signal product end end end $IBOOFMΫϥεͷ࣮૷ UBLFϝιου $POTVNFSΦϒδΣΫτͷதͰ UBLFϝιου͕ݺ͹ΕΔ ‎ϓʔϧ͔ΒQSPEVDU͕औΓग़͞ΕΔ ‎ϓʔϧʹۭ͖͕Ͱ͖Δ
  11. $IBOOFMΫϥεͷ࣮૷ UBLFϝιου class Channel def initialize(size) # … def put(product)

    # … def take @mutex.synchronize do # … product = @products.pop @cond.signal product end end end $POEJUJPO7BSJBCMFTJHOBM ॲཧͷ଴ػΛղআ͠ɺ ࠶ͼϩοΫΛऔಘͰ͖ΔΑ͏ ৚݅ม਺΁௨஌ΛૹΔ ϓʔϧʹۭ͖͕Ͱ͖ͨ͜ͱΛ ৚݅ม਺΁௨஌͢Δ
  12. $IBOOFMΫϥεͷ࣮૷ UBLFϝιου class Channel def initialize(size) # … def put(product)

    # … def take @mutex.synchronize do # … product = @products.pop @cond.signal product end end end $POEJUJPO7BSJBCMFTJHOBM ॲཧͷ଴ػΛղআ͠ɺ ࠶ͼϩοΫΛऔಘͰ͖ΔΑ͏ ৚݅ม਺΁௨஌ΛૹΔ ϓʔϧʹۭ͖͕Ͱ͖ͨ͜ͱΛ ৚݅ม਺΁௨஌͢Δ ‎QVUϝιουͷ଴ػΛղআ͢Δ
  13. $IBOOFMΫϥεͷ࣮૷ ࠶ͼQVUϝιου class Channel def initialize(size) # … def put(product)

    @mutex.synchronize do while @products.size >= @size @cond.wait(@mutex) end @products.push product puts "#{Thread.current.name} produces #{product}." @cond.signal end end def take # … end  ॲཧΛ࠶։ͨ͠Β  QSPEVDUΛϓʔϧʹೖΕΔ
  14. $IBOOFMΫϥεͷ࣮૷ ࠶ͼQVUϝιου class Channel def initialize(size) # … def put(product)

    @mutex.synchronize do while @products.size >= @size @cond.wait(@mutex) end @products.push product puts "#{Thread.current.name} produces #{product}." @cond.signal end end def take # … end QVUϝιουͷதͰ΋ ৚݅ม਺΁ͷ௨஌Λߦͳ͍ͬͯΔ
  15. $IBOOFMΫϥεͷ࣮૷ ࠶ͼUBLFϝιου class Channel def initialize(size) # … def put(product)

    # … def take @mutex.synchronize do while @products.size <= 0 @cond.wait(@mutex) end product = @products.pop @cond.signal product end end end ˞UBLFϝιου͸QVUϝιουΛ ɹ൓సͤͨ͞Α͏ͳॲཧΛߦͳ͍ͬͯΔ ϓʔϧ͕ۭͰ͋Δ৔߹ɺ ϓʔϧ͔ΒQSPEVDUΛऔΔ ͜ͱ͕Ͱ͖ͳ͍ ‎৚݅ม਺Λ࢖ͬͯ ϓʔϧʹQSPEVDU͕ೖΔ·Ͱ ͜͜ͰॲཧΛ଴ػ͢Δ  ॲཧΛ࠶։ͨ͠Β  QSPEVDUΛϓʔϧ͔ΒऔΓग़͢
  16. $POTVNFSΫϥεͷ࣮૷ class Consumer def initialize(name, channel) Thread.current.name = name @channel

    = channel end def run loop do product = @channel.take puts "#{Thread.current.name} consumes #{product}." end end end # εϨουͷ໊લΛอଘ # ChannelΦϒδΣΫτ $IBOOFM͔ΒQSPEVDUΛऔΓग़͢
  17. $POTVNFSΫϥεͷ࣮૷ class Consumer def initialize(name, channel) Thread.current.name = name @channel

    = channel end def run loop do product = @channel.take puts "#{Thread.current.name} consumes #{product}." end end end $IBOOFM͔ΒQSPEVDUΛऔΓग़͢ ׬੒ʂ # εϨουͷ໊લΛอଘ # ChannelΦϒδΣΫτ
  18. 3BDUPSΛ࢖͏ϓϩάϥϜͷશମ૾ class Producer # … class Consumer # … channel

    = Ractor.new { # … } numbering = Ractor.new { # … } producers = 3.times.map { Ractor.new { # … } } consumers = 3.times.map { Ractor.new { # … } } producers.each(&:take) consumers.each(&:take) 1SPEVDFSΫϥε $POTVNFSΫϥε $IBOOFM3BDUPS ϝΠϯϓϩάϥϜ ࠾൪ػ3BDUPS
  19. ϝΠϯϓϩάϥϜͷ࣮૷ producers = 3.times.map { |i| Ractor.new(channel, numbering, name: "P-#{i

    + 1}") do |ch, num| Producer.new(ch, num).run end } consumers = 3.times.map { |i| Ractor.new(channel, name: "C-#{i + 1}") do |ch| Consumer.new(ch).run end } producers.each(&:take) consumers.each(&:take) ͭͷ3BDUPSͰ 1SPEVDFSΦϒδΣΫτΛ ੜ੒͠ɺՔಇͤ͞Δ ͭͷ3BDUPSͰ $POTVNFSΦϒδΣΫτΛ ੜ੒͠ɺՔಇͤ͞Δ
  20. ϝΠϯϓϩάϥϜͷ࣮૷ producers = 3.times.map { |i| Ractor.new(channel, numbering, name: "P-#{i

    + 1}") do |ch, num| Producer.new(ch, num).run end } consumers = 3.times.map { |i| Ractor.new(channel, name: "C-#{i + 1}") do |ch| Consumer.new(ch).run end } producers.each(&:take) consumers.each(&:take) ֤3BDUPSͷ࣮ߦΛ଴ͪ߹ΘͤΔ Ҿ਺ͱ֤ͯ͠3BDUPSͷ໊લͱ $IBOOFMͱ࠾൪ػΛ౉͢ Ҿ਺ͱ֤ͯ͠3BDUPSͷ໊લͱ $IBOOFMΛ౉͢
  21. 1SPEVDFSΫϥεͷ࣮૷ class Producer def initialize(channel, numbering) @channel = channel @numbering

    = numbering end def run # … end private def issue_product_no # … end end # Channel Ractor # ࠾൪ػ3BDUPS QSPEVDU൪߸Λൃߦ͢ΔͨΊͷϝιου
  22. class Producer def initialize(channel, numbering) # … def run loop

    do product_no = issue_product_no # … end end private def issue_product_no @numbering.send Ractor.current # … end end 3BDUPSTFOE ⾩SFDFJWF  ର৅ͷ3BDUPSΦϒδΣΫτ΁ ϝοηʔδΛૹΔ ࠾൪ػʹ͜ͷ3BDUPSࣗ਎ΛૹΔ 1SPEVDFSΫϥεͷ࣮૷ SVOJTTVF@QSPEVDU@OPϝιου
  23. ϝΠϯϓϩάϥϜͷ࣮૷ ࠾൪ػ3BDUPS numbering = Ractor.new(no = 0) do |no| loop

    do no += 1 producer = Ractor.receive producer.send no end end ड͚औͬͨ1SPEVDFS3BDUPSʹQSPEVDU൪߸Λฦૹ͢Δ 1SPEVDFS3BDUPSΛड͚औΔ 3BDUPSSFDFJWF ⾩TFOE  ࣗ਎ͷJODPNJOHQPSU͔Β ϝοηʔδΛड͚ೖΕΔ QSPEVDU൪߸ΛΧ΢ϯτΞοϓ͢Δ
  24. 1SPEVDFSΫϥεͷ࣮૷ SVOJTTVF@QSPEVDU@OPϝιου class Producer def initialize(channel, numbering) # … def

    run loop do product_no = issue_product_no # … end end private def issue_product_no @numbering.send Ractor.current Ractor.receive end end ࠾൪ػ͔Βड͚औͬͨQSPEVDU൪߸Λฦ͢
  25. class Producer def initialize(channel, numbering) # … def run loop

    do product_no = issue_product_no @channel.send ["Product no. #{product_no}”, Ractor.current] end end private def issue_product_no @numbering.send Ractor.current Ractor.receive end end ࠾൪ͨ͠QSPEVDUͱɺ͜ͷ3BDUPSࣗ਎Λ$IBOOFMʹૹΔ 1SPEVDFSΫϥεͷ࣮૷ SVOJTTVF@QSPEVDU@OPϝιου
  26. ϝΠϯϓϩάϥϜͷ࣮૷ $IBOOFM3BDUPS channel = Ractor.new do loop do product, producer

    = Ractor.receive puts “#{producer.name} produces #{product}." Ractor.yield product end end 3BDUPSZJFME ⾩UBLF  ࣗ਎ͷPVUHPJOHQPSU͔Β ϝοηʔδΛૹΓग़͢ 1SPEVDFS3BDUPS͔ΒσʔλΛड͚औͬͯ ͦͷ··$POTVNFS3BDUPS΁ૹΓग़͚ͩ͢ʂ QSPEVDUΛૹΓग़͢ QSPEVDUΛड͚औΔ
  27. $POTVNFSΫϥεͷ࣮૷ class Consumer def initialize(channel) @channel = channel end def

    run loop do product = @channel.take puts "#{Ractor.current.name} consumes #{product}" end end end 3BDUPSUBLF ⾩ZJFME  ର৅ͷ3BDUPSΦϒδΣΫτ͔Β ϝοηʔδΛҾ͖ग़͢ # Channel Ractor $IBOOFM͔ΒૹΓग़͞ΕͨQSPEVDUΛड͚औΔ
  28. $POTVNFSΫϥεͷ࣮૷ class Consumer def initialize(channel) @channel = channel end def

    run loop do product = @channel.take puts "#{Ractor.current.name} consumes #{product}" end end end 3BDUPSUBLF ⾩ZJFME  ର৅ͷ3BDUPSΦϒδΣΫτ͔Β ϝοηʔδΛҾ͖ग़͢ ׬੒ʂ # Channel Ractor $IBOOFM͔ΒૹΓग़͞ΕͨQSPEVDUΛड͚औΔ