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

Actor, Thread and me (RubyKaigi2015)

Actor, Thread and me (RubyKaigi2015)

Everybody says. Actor helps to solve the multithreading problem. Actor is awesome. Threads are 💩

Really?

An actor model is "just a model", just like MVC.

Today, Recap what Actor Model is.

40f4d1f2e77078955bd01e9fb4a503ba?s=128

seki at druby.org

December 13, 2015
Tweet

Transcript

  1. Actor, Thread and me seki@ruby-lang.org

  2. slide sponsors 嫣鹈،ؙة٦ךֿהח鑫׃ֻז׸׷ؔٝٓ؎ٝ⿫⸇דֹ׷؝ىُصذ؍׌״  TBQQPSPCFBNHJUIVCJP ؟ٝٓ؎ؤ⳿ꨡד遤ֻ3VCZ8PSME$POGFSFODFծ嫣䎃㥨鐰㹋倵⚥דׅկ勻䎃 ׮װ׶תׅךדծֶ㉏ְさ׻ׇ♴ְׁZBODZB 虠加歕ջ梾楤㼔Ꟍ枾䒍莔ռ׀勻䏄ֶ䖉׍׃גֶ׶תׅ!PHJKVO սט׷⹫վ䎃剢ַ׵ך➬✲!1613- ջأذ؍٦ـؤռ䋆涪㡰⚥!NB

    ջأذ؍٦ـؤռ顠ְת׃׋!WFTUJHF@ ջأذ؍٦ـؤռ顠ְתׅ!USBDL ֿ׿ח׍כֿ׿ח׍כ!IJCBSJZB
  3. more slide sponsors ׻׋׃׋׍ծה׷ן٦ׅה!USJDLOPUFT הגַכ剢דׅկ✮㹀ծ甧גגְֶג♴ְׁי!NBNF 5BLBZVLJ,BNJZBNB!UBLLJJ ת׌ֹ׭זְַ׵ծ罋ִתׅ![[BL@KQ E3VCZח״׷ⴓ侔٥8FCفؚٗٓىؚٝ ؔ٦ي爡F#PPL4UPSF IUUQ

    FTUPSFPINTIBDPKQUJUMFT1!IJTBTIJN ׉׸ד׮EFGBVMU@TDPQF⢪ְתַׅ!TVHJOPZ ؔٔآشٕ5ءٍخך5.*9ծ倜㉀ㅷؙٓحثغحؚ׮㥨鐰涪㡰⚥!JHBJHB ׫זׁתծTFLJ眍׾ֶ嚂׃׫ֻ׌ְׁկ䊛䃵歲꥔ך倯כծLBXBTBLJSCծZPLPIBNBSC׾ ֶ鑐׃ֻ׌ְׁկ,ذٖؽך飑ⰅכծTFLJׁ׿穗歋ד׀湱锑ְ׋׌ֽ׷ה׀⼿⸂׃תׅկ!UTVCPJ
  4. T-shirts sponsors TV[VSJKQN@TFLJ

  5. sticker sponsors

  6. Pragmatic Bookshelf Author

  7. ΋͏ઈ൛ out of print

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

    after the 1st edition
  9. Agenda ΞΫλʔϞσϧ ࣮૷ - Actor Model - Implementation

  10. Actor is better than Thread ϚϧνεϨουͰൃੜ͢Δ໰୊͕ղܾ͢Δ εϨουͰਖ਼͘͠ॻ͘ͷ͸Ή͔͍ͣ͠ ΞΫλʔͳΒ؆୯ʹॻ͚Δ εϨου͸ ຊ౰ʁ

    Everybody says. Actor helps to solve the multithreading problem. Actor is awesome. Threads are . Really?
  11. None
  12. Actor and Thread εϨουؒͷσʔλͷަ׵Λ੍ݶ ෳ਺ͷεϨου͕σʔλΛॻ͖׵͑ͳ͍ ΞΫλʔͳΒ؆୯ͩ ͑ʁͦ͜ͳͷʁ - Control passing

    data between threads - Properly handle changeing data between threads - So, that's the point?
  13. Process and Thread εϨουͱϓϩηεͷҧ͍ ϝϞϦۭؒΛڞ༗Ͱ͖Δ ϝϦοτͰ͋ΓσϝϦοτͰ͋Δ ͭ·ΓͦΕ͕ͦ͜ಛ௃Ͱ͋Δ ϓϩηεͰ͍͍ͷͰ͸ʂ Difference between

    Thread / Process - Could share memory space - So, that's one of the big characteristics of threads Well, couldn't it be process ...!!
  14. Actor Model, Again ΞΫλʔϞσϧΛ͓͞Β͍͍ͨ͠ Recap what Actor Model is

  15. Model ΞΫλʔϞσϧ͸ͨͩͷϞσϧ MVCΈ͍ͨʹͨͩͷϞσϧ ໛ܕ ΑΓྑ͍εϨουͰ͸ͳ͍ͱࢥ͏ An actor model is "just

    a model;" - Just like MVC An actor model probably isn't a "better thread"
  16. Actor Model Actor Message Ether

  17. Message ѼઌΛࢦఆ͢Δ Specify the destination

  18. Actor ࣮ߦओମ ୭ʹ΋अຐ͞Εͳ͍ ࣗ෼ͷϖʔεͰ࢓ࣄ͢Δ - Execution subject - Cannot be

    interrupted by anyone - Work at your own pace
  19. Messaging System ActorͱActorͷؒͰ
 ϝοηʔδΛ఻೻͢Δ Passing message between Actors

  20. Ether (Æther) ͔ͭͯޫͷ೾Λ఻͑Δഔ࣭ͱͯ͠Ծ૝͞Ε͍ͯͨ෺࣭ Ethernetͷޠݯ? ͔͍͍͔ͬ͜Βࠓ೔͸Τʔςϧ - Æther used to be

    thought as medium that transmit llight waves - Originated from Ethernet ? - "Æther" sounds good to me, so I'll call Messaging System "Ether" today
  21. Send ࣗ෼ͷ౎߹ͷྑ͍࣌ʹ
 ϝοηʔδΛૹΔ͜ͱ͕Ͱ͖Δ ฦ৴͕ඞཁͳΒͦΕ΋
 ϝοηʔδͰ΋Β͏ Could send messages whenever you

    wish If necessary, you could also receive message for a reply
  22. Receive ࣗ෼ͷ౎߹ͷྑ͍࣌ʹࣗ෼Ѽͷ
 ϝοηʔδΛड͚औΔ ॱෆಉ Could receive messages whenever you wish.

    Received in random order
  23. ͜Ε͚ͩͷಓ۩ͰγεςϜΛ ॻ͜͏ ଞʹActorͷੜ੒΋͋Δ͚ͲׂѪ ےτϨΈ͍ͨͳײ͡ ࢥߟ࣮ݧʁ Let's try to make system

    with these instruments - Skip other topics like Actor Creation - Maybe a thought experiment?
  24. ਎ۙʹ͋ΔΞΫλʔϞσϧ Win32ΞϓϦͳͲͷEvent Drivenͳ΍ͭ Ͱ΋εϨου͕ඞཁʹͳͬͨΜͩΑͳ ϞϊεϨουͰselectଐΛ࢖ͬͨsocketϓϩ άϥϛϯάͱ͔ N̋de.js͸ʁ ͍ΖΜͳγεςϜͰ΋ݟΒΕΔ Common examples

    of Actor Model - MFC, - Single threaded socket client/server programming using select - Like these, you can see it in other systems
  25. Simple Worker 1. Receive 2. Working 3. Send

  26. client / server 1. Receive 2. Working 3. Send 0.

    Send 4. Receive
  27. Simple Worker def oso_matz_RPC request = ... ether.send(:oso_matz, request) return

    ether.receive end while true request = ether.receive result = do_it(request) ether.send(request.from, result) end
  28. ࣗ෼ͷ౎߹͚ͩͰಈ͘ ୭ʹ΋ׯব͞Εͳ͍ ౎߹ͷྑ͍࣌ʹಡΈɺ౎߹ͷྑ͍࣌ʹॻ͘ ؆୯ʂ҆৺ʂ εϨουͳΜͯ ຊ౰͔ʁ Works at your convenience

    - No one interrupts you, Read and write whenever you wish - Reliable and easy to use Is this true ?
  29. Worker͕ڠௐ͢Δέʔε ୭͔ͷ݁ՌΛ࢖ͬͯ͞Βʹܭࢉ͢Δέʔε Collaborative workers When you work with the results

    of your collaborator's calculation
  30. ୭͔ͷ݁ՌͰܭࢉ while true request = ether.receive # jushi_matz RPC ether.send(:choro_matz,

    task1) task1_value = ether.receive result = do_it(request, task1_value) ether.send(request.from, result) end SFDFJWF✳א 2種類のメッセージ When you work with the results
  31. 2छྨͷϝοηʔδΛѻ͏ 1. Receive 4. Do it 2. Send task1 3.

    Receive task1 5. Send SFDFJWF✳א 2種類のメッセージ 2 types of messages
  32. ͋ͱͰ΍Δ pending = [] while true request = pending.shift ||

    ether.receive ether.send(:choro_matz, task1) while true message = ether.receive if message.reply? task1_value = message break end pending << message end result = do_it(request, task1_value) ether.send(request.from, result) end 欲しいものを待つ あとでやるリスト Do it Later - wait for reply message - with list of Do it Later あとでやるリスト
  33. ͋ͱͰ΍ΔϦετ 1. Receive 4. Do it 2. Send task1 3.

    Receive task1 5. Send 処理できないやつをあとでやる Stock and process do-it-later strategy
  34. ͋ͱͰ΍Δ࡞ઓ... ࣗ෼ͷ౎߹ͷྑ͍࣌ʹ΍ΔΑ ΍Γ͔͚ͷ͕ऴΘ͔ͬͯΒ࣍ͷཁٻΛ΍Δ ࣗ෼͸͏·͘ߦ͘ - Process whenever you're ready -

    Finish working process before moving on to the next request - For myself, it works fine
  35. ૬ޓʹґଘ͢Δ෦෼͕͋ͬͨΒ... ݏͳ༧ײ͕͢Δ Bad smells... - What if there were mutual

    dependency between workers..
  36. "͋ͱͰ΍Δ"Λ࣋ͬͨ··͓ޓ͍ʹreplyΛ଴ͬͪΌ͏ ݏͳ༧ײ͕͢Δ They wait for their next reply, even though

    the have their stocks at hand
  37. 20ੈل ػೳ෼ࢄ ͜ͷόά΍ͬͨ͜ͱ͋Δ These bugs sound familiar - 20th century

    - Functional distribution
  38. Ӆ͞Εͨґଘ͕͋ͬͨ ࣌ʑɺΈΜͳ͕reply଴ͪʹͳΔ ୭΋ࢭ·ͬͯͳ͍͚ͲγεςϜ͸ࢭ·ͬͯΔ Hidden dependency...revealed - All of the workers

    wait for their replies once in a while - Everyone is trying to work, but the system itself stops
  39. ·͞ʹnon-blocking ฦ৴ʹݶΒͣෳ਺ͷϝοηʔδΛ଴ͭέʔε Future/PromiseͰͷ݁Ռ໰͍߹Θͤͱ͔ ෳ਺ͷΠϕϯτΛ଴ͬͯॲཧ͢Δͱ͔ (ڞ༗ࢿݯͱ͔΋) This WAS actually "non-blocking" When

    multiple messages, including replies, are held by workers - e.g. Query for the results between Future and Promise - e.g. Start processing when some events finish - Not only messages but the other shared resources
  40. ڞ༗ࢿݯ΁ͷૢ࡞͸ڠௐ͢Δඞཁ͕͋Δ ΞΫλʔͱߟ͑ͯ෼ੳ͢Δͱ͍͍Αʂ খωλ/ڞ༗ࢿݯͷૢ࡞ e.g. How to use shared resources between

    Actors? I think shared is an actor.
  41. ͋ͱͰ΍Δ࡞ઓ... μϝͩͬͨ ࣗ෼ͷ౎߹ͷྑ͍࣌ʹಡΈɺॲཧ͠ɺॻ͘ ΈΜͳ͕ͦ͏Ͱ͖Δʹ͸Ͳ͏͢Δ͔ʁ Do-it -later strategy. It doesn't work.

    How do you make it so that everybody can read, process, and write at their own pace?
  42. ͦ͏͍͏ঢ়گ͕ѱ͍ શͯͷΞΫλʔ͕୭ʹ΋ґଘ͠ͳ͍΂͖ʁ ΋͔ͯ͠͠αϒϧʔνϯͰ͍͍ʁ ͦΕͳΒΞΫλʔͷҙٛ͸... The issue is this situation -

    Every actor should only depend on themselves -- Does subroutine work for this? --- if then, what's the meaning of Actor?
  43. ͦ͏͍͏ঢ়گ͕ѱ͍ ਖ਼͘͠ॻ͚͹͏·͍͘͘ͷʹʂ ͍͍ͨͯͦ͏ ʂ - write it the right way,

    and it will work fine! -- This applies to usually everything
  44. ͦ͏͍͏ঢ়گ͕ѱ͍ ݁Ռʹڵຯ͕ͳ͍ϒϩʔυΩϟετܥ޲͖ʁ It may work if you only do broadcasting.

  45. ͦ͏͍͏ঢ়گΛड͚ೖΕΔ ΞΫλʔ͸Ϟσϧ / ےτϨ / ࢥߟ࣮ݧ Ή͠Ζঢ়گΛड͚ೖΕΑ͏ʂ Accept these situations

    - Actor is a model and a thought experiment -- Accept these difficult situations
  46. ͜͏ͨ͠ΒͲ͏ͩΖ͏ ࣗ෼͸ΈΜͳͷ౎߹ʹ߹ΘͤΔɺͱఘΊΔ ࢓ࣄͷ్தͰ΋Ͱ͖Δ͚͖ͩͭ͋͏ My suggestions: - Each actor waits and

    serves others first, even if you have any process left
  47. event driven while true event = ether.receive case event.kind when

    :request do_request(event) when :reply_choro_matz do_reply_choro_matz(event) .... end end
  48. ͋͋callbackͶ while true event = ether.receive case event.kind when :request

    do_request(event) when :reply_choro_matz do_reply_choro_matz(event) .... end end callback はこの分岐が 動的になっただけ Ah, callbacks - This branch just turned dynamic for callback
  49. ్தܦաΛϝϞ͢ΔҨݴ࡞ઓ def do_request(event) uid = push_context { :from => event.form

    } ether.send(:choro_matz, [args, uid]) end def do_reply_choro_matz(reply) uid = reply.uid context = pop_context(uid) value = do_oso_matz(context, reply) ether.send(context[:from], value) end save context restore context Save-the-progress strategy
  50. ॲཧͷྲྀΕΛࣗવʹॻ͚ͳ͍ ίϯςΩετΛཅʹѻΘͳ͖ΌͳΒͳ͍ ॲཧΛࣗવͳྲྀΕͱͯ͠ॻ͖ʹ͍͘ while true request = ether.receive # jushi_matz

    RPC ether.send(:choro_matz, task1) task1_value = ether.receive result = do_it(request, task1_value) ether.send(request.from, result) end 元は単純だったのに Difficult to write the process naturally - It was simple originally... (but become complex)
  51. ෳ਺ͷίϯςΩετ͕͋ͬͨ ࣗ෼͚͕ͩσʔλΛૢ࡞͢Δͷ͕҆શͷࠜڌ ͍·͸ෳ਺ͷίϯςΩετ͕ڞ༗͢Δ There were contexts - Specifying who handles

    data is important for safety - But now they are handled in some contexts
  52. Fiberͷ࢖͍ํʹࣅͯΔʁ ϞϊεϨουͰෳ਺ͷίϯςΩετ ໌ࣔతͳίϯςΩετ੾Γସ͑ ಉ͡ऑ఺͕͋Δ Similar to Fiber? - Some contexts

    in a single thread - Explicit context switch - Same weak point here
  53. ࢭ·Δ ϒϩοΫ͢Δॲཧ͕͋ͬͨΒશ෦ࢭ·Δ ϒϩοΫͯ͠΋શମ͸ಈ͔͍ͨ͠ ͦ͜ͰϚϧνεϨουͰ͢Αʂ ʢͦ΋ͦ΋Fiber೉͍͠͠ʣ Halt - Halt if there

    is a process that blocks other one - But want to run a whole system if there is - This is good timing to use multi threads
  54. ͓͢͢Ί γεςϜશମ͸ΞΫλʔϞσϧͰߟ͑Δ ΞΫλʔͷத਎͸ϚϧνεϨου Recomended way - Think about a whole

    system using Actor Model - In this context, Actor is multi thread
  55. ͠͹Β͓͘଴͍ͪͩ͘͞ ✓ ΞΫλʔ͓͞Β͍ͨ͠ ✓ ͓͢͢Ίͨ͠ ✓ 'JCFSωλ

  56. github/seki/bartender Fiber೉ͦ͠͏ͳͷͰ࢖ͬͯΈͨʂ selectΛগ͠ந৅Խ͢ΔϑϨʔϜϫʔΫ BTW - Fiber seems difficult, but i

    tried. - This is a framework to abstract a 'select' a little
  57. Bartender::App App#[]=(event, fd, callback) ίʔϧόοΫͷొ࿥ɻ Ϣʔβʔσʔλ͸ͳ͠ɻ⇦ MethodΦϒδΣΫτΛ౉ͤ͹͍͍͡ΌΜ App#delete(event, fd) App#run

    ϝΠϯϧʔϓ App#[]= - registers a callback - Pass method object
  58. Ҏ্ʂ [event, fd]ͱϝιουΛ݁ͼ͚ͭΔ͚ͩ That's all! - That's the point of

    this framework
  59. ReaderͱWriter ͜ΕͰ͸ෆศͳͷͰϢʔςΟϦςΟʔΛ non-block I/OΛblock෩ʹ͢Δ blockͦ͠͏ʹͳͬͨΒ࣮ߦݖΛख์͢ Fiber.yieldͶ - This is not

    useful so let's provide a utility - Block-ish non-blocking I/O - If going to block, Fiber yield.
  60. Bartender::Reader Reader#read(n) nΦΫςοτಡΉ Reader#read_until(sep="\r\n", chunk_size=8192) Reader#readln ηύϨʔλ·Ͱʢߦ຤·ͰʣಡΜͰฦ͢

  61. 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
  62. readͷ಺ଆͷ_read͕ϛι Θ͔Γʹ͍͚͘Ͳ͕͜͜Πέϝϯ The _read insight head is the point -

    seems difficult, but hang in there.
  63. 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
  64. 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 Method object
  65. 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 back to Bartender
  66. 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 Unregister callback
  67. dRubyϓϩτίϧ ࣮ݧ༻ΫϥΠΞϯτॻ͘ͷ͕໘౗ dRubyͷϓϩτίϧΛ࿩ͤΔαʔόΛॻ͜͏ Writing a client for experiment is tough

    So let's write a server that understands dRuby protocol
  68. dRubyϓϩτίϧ ಈ͍ͨʂ͕͢͞ࢲʂ I did it! It works!

  69. 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 not important
  70. 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 not important
  71. 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し まくる Don't care about I/O blocking and context switch Just read it sequentially
  72. BartenderͰͷFiberͷ࢖͍ํ I/OͷϒϩοΫͷࡍʹ࣮ߦݖΛख์͢ ϑϨʔϜϫʔΫ͕׬ྃΛଊ͑ͯ࠶։͢Δ - Fiber.yield when I/O block happens -

    The framework catches its finish and then resumes the fiber
  73. ղܾ͠ͳ͔ͬͨ͜ͱ ͦͷϝιου͸௕͍ॲཧΛ͢Δͷʁ ஌Δํ๏͕ͳ͍ Θ͔ͬͨͱ͜ΖͰͲ͏͍͍͔ͯ͠Θ͔Βͳ͍ εϨουͷํ͕Ϛγ Things not solved yet -

    Halt when calling the method that blocks - Thread is relatively better
  74. ͠͹Β͓͘଴͍ͪͩ͘͞ ✓ #BSUFOEFSࣗຫ ✓ ΤʔςϧΛ࡞Ζ͏

  75. ࣗ෼ͷΤʔςϧΛ࡞Ζ͏ Queue TupleSpace Write your own Ether

  76. શһQueue࣋ͬͯΔ ΦϒδΣΫτΛThreadͱQueueͰแΜͰΈͨ ΦϒδΣΫτ͕QueueΛ࣋ͭ ϝιουݺͼग़͠ΛશͯQueue΁ ௚ྻԽ Let all objects have a

    queue
  77. ࣗ෼༻Queue

  78. method_missing class ActorsOffice def initialize(actor) @queue = Queue.new @thread =

    Thread.new(actor) do catch(actor) do while true msg, arg, blk = @queue.pop actor.__send__(msg, *arg, &blk) end end end end def __thread__; @thread; end def method_missing(m, *a, &b) @queue.push([m, a, b]) end end
  79. ॻ͍͚ͨͲ ࢖Θͳ͔ͬͨʂ ͳΜͰ΋௚ྻԽ͍ͨ͠ਓ޲͚ I wrote, but not used. It's just

    for those who like to serialize
  80. தԝूݖܕ Rinda::TupleSpace Centralized structure

  81. தԝूݖܕ Centralized structure

  82. ether = Rinda::TupleSpace _, message = ether.take([:oso_matz, nil]) ether.write([message[:from], {

    :reply => "Hi!" }) message = { :from => :choro_matz, :greeting => "Hello, World." } ether.write([:oso_matz, message]) ether.write([:todo_matz, message])
  83. ·͋ಈ͘ dRubyͱ૊Έ߹ΘͤΕ͹ϓϩηεؒ΋ಈ͘Α Α͘࢖ͬͯΔ Yes, it works. - You can run

    it between processes / machines by using dRuby - I use it, frequently
  84. ΤʔςϧΛॻ͍ͯؾ͍ͮͨ ΞΫλʔͱΤʔςϧͷؔ܎΋ΞΫλʔʁ Ϟσϧͱͯ͠ͷΞΫλʔ͸Ͳ͜ʹͰ΋͋Δͷ Ͱ͸ʂ As you may notice when listening

    to my talk, the relationship between Actor and Ether may be Actor Model, too
  85. ·ͱΊ Ϟσϧͱͯ͠ͷΞΫλʔΛ͓͞Β͍ ΑΓྑ͍εϨου͡Όͳ͍ؾ෼Λڞ༗ Ͱ͖ͨʁ Summary - Recap what Actor Model

    is - Feel like it's not just a better Thread, is it?
  86. ӳ༁͋Γ͕ͱ u @yasulab @akira_nise @tenderlove