Slide 1

Slide 1 text

Actor, Thread and me [email protected]

Slide 2

Slide 2 text

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

Slide 3

Slide 3 text

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

Slide 4

Slide 4 text

T-shirts sponsors TV[VSJKQN@TFLJ

Slide 5

Slide 5 text

sticker sponsors

Slide 6

Slide 6 text

Pragmatic Bookshelf Author

Slide 7

Slide 7 text

΋͏ઈ൛ out of print

Slide 8

Slide 8 text

ॳ࡮Γ10प೥ dRuby ʹΑΔ ؔকढ़ஶ ෼ࢄ ɾ Web ϓϩάϥϛϯά 10th anniversary after the 1st edition

Slide 9

Slide 9 text

Agenda ΞΫλʔϞσϧ ࣮૷ - Actor Model - Implementation

Slide 10

Slide 10 text

Actor is better than Thread ϚϧνεϨουͰൃੜ͢Δ໰୊͕ղܾ͢Δ εϨουͰਖ਼͘͠ॻ͘ͷ͸Ή͔͍ͣ͠ ΞΫλʔͳΒ؆୯ʹॻ͚Δ εϨου͸ ຊ౰ʁ Everybody says. Actor helps to solve the multithreading problem. Actor is awesome. Threads are . Really?

Slide 11

Slide 11 text

No content

Slide 12

Slide 12 text

Actor and Thread εϨουؒͷσʔλͷަ׵Λ੍ݶ ෳ਺ͷεϨου͕σʔλΛॻ͖׵͑ͳ͍ ΞΫλʔͳΒ؆୯ͩ ͑ʁͦ͜ͳͷʁ - Control passing data between threads - Properly handle changeing data between threads - So, that's the point?

Slide 13

Slide 13 text

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 ...!!

Slide 14

Slide 14 text

Actor Model, Again ΞΫλʔϞσϧΛ͓͞Β͍͍ͨ͠ Recap what Actor Model is

Slide 15

Slide 15 text

Model ΞΫλʔϞσϧ͸ͨͩͷϞσϧ MVCΈ͍ͨʹͨͩͷϞσϧ ໛ܕ ΑΓྑ͍εϨουͰ͸ͳ͍ͱࢥ͏ An actor model is "just a model;" - Just like MVC An actor model probably isn't a "better thread"

Slide 16

Slide 16 text

Actor Model Actor Message Ether

Slide 17

Slide 17 text

Message ѼઌΛࢦఆ͢Δ Specify the destination

Slide 18

Slide 18 text

Actor ࣮ߦओମ ୭ʹ΋अຐ͞Εͳ͍ ࣗ෼ͷϖʔεͰ࢓ࣄ͢Δ - Execution subject - Cannot be interrupted by anyone - Work at your own pace

Slide 19

Slide 19 text

Messaging System ActorͱActorͷؒͰ
 ϝοηʔδΛ఻೻͢Δ Passing message between Actors

Slide 20

Slide 20 text

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

Slide 21

Slide 21 text

Send ࣗ෼ͷ౎߹ͷྑ͍࣌ʹ
 ϝοηʔδΛૹΔ͜ͱ͕Ͱ͖Δ ฦ৴͕ඞཁͳΒͦΕ΋
 ϝοηʔδͰ΋Β͏ Could send messages whenever you wish If necessary, you could also receive message for a reply

Slide 22

Slide 22 text

Receive ࣗ෼ͷ౎߹ͷྑ͍࣌ʹࣗ෼Ѽͷ
 ϝοηʔδΛड͚औΔ ॱෆಉ Could receive messages whenever you wish. Received in random order

Slide 23

Slide 23 text

͜Ε͚ͩͷಓ۩ͰγεςϜΛ ॻ͜͏ ଞʹActorͷੜ੒΋͋Δ͚ͲׂѪ ےτϨΈ͍ͨͳײ͡ ࢥߟ࣮ݧʁ Let's try to make system with these instruments - Skip other topics like Actor Creation - Maybe a thought experiment?

Slide 24

Slide 24 text

਎ۙʹ͋ΔΞΫλʔϞσϧ 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

Slide 25

Slide 25 text

Simple Worker 1. Receive 2. Working 3. Send

Slide 26

Slide 26 text

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

Slide 27

Slide 27 text

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

Slide 28

Slide 28 text

ࣗ෼ͷ౎߹͚ͩͰಈ͘ ୭ʹ΋ׯব͞Εͳ͍ ౎߹ͷྑ͍࣌ʹಡΈɺ౎߹ͷྑ͍࣌ʹॻ͘ ؆୯ʂ҆৺ʂ εϨουͳΜͯ ຊ౰͔ʁ Works at your convenience - No one interrupts you, Read and write whenever you wish - Reliable and easy to use Is this true ?

Slide 29

Slide 29 text

Worker͕ڠௐ͢Δέʔε ୭͔ͷ݁ՌΛ࢖ͬͯ͞Βʹܭࢉ͢Δέʔε Collaborative workers When you work with the results of your collaborator's calculation

Slide 30

Slide 30 text

୭͔ͷ݁ՌͰܭࢉ 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

Slide 31

Slide 31 text

2छྨͷϝοηʔδΛѻ͏ 1. Receive 4. Do it 2. Send task1 3. Receive task1 5. Send SFDFJWF✳א 2種類のメッセージ 2 types of messages

Slide 32

Slide 32 text

͋ͱͰ΍Δ 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 あとでやるリスト

Slide 33

Slide 33 text

͋ͱͰ΍ΔϦετ 1. Receive 4. Do it 2. Send task1 3. Receive task1 5. Send 処理できないやつをあとでやる Stock and process do-it-later strategy

Slide 34

Slide 34 text

͋ͱͰ΍Δ࡞ઓ... ࣗ෼ͷ౎߹ͷྑ͍࣌ʹ΍ΔΑ ΍Γ͔͚ͷ͕ऴΘ͔ͬͯΒ࣍ͷཁٻΛ΍Δ ࣗ෼͸͏·͘ߦ͘ - Process whenever you're ready - Finish working process before moving on to the next request - For myself, it works fine

Slide 35

Slide 35 text

૬ޓʹґଘ͢Δ෦෼͕͋ͬͨΒ... ݏͳ༧ײ͕͢Δ Bad smells... - What if there were mutual dependency between workers..

Slide 36

Slide 36 text

"͋ͱͰ΍Δ"Λ࣋ͬͨ··͓ޓ͍ʹreplyΛ଴ͬͪΌ͏ ݏͳ༧ײ͕͢Δ They wait for their next reply, even though the have their stocks at hand

Slide 37

Slide 37 text

20ੈل ػೳ෼ࢄ ͜ͷόά΍ͬͨ͜ͱ͋Δ These bugs sound familiar - 20th century - Functional distribution

Slide 38

Slide 38 text

Ӆ͞Εͨґଘ͕͋ͬͨ ࣌ʑɺΈΜͳ͕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

Slide 39

Slide 39 text

·͞ʹ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

Slide 40

Slide 40 text

ڞ༗ࢿݯ΁ͷૢ࡞͸ڠௐ͢Δඞཁ͕͋Δ ΞΫλʔͱߟ͑ͯ෼ੳ͢Δͱ͍͍Αʂ খωλ/ڞ༗ࢿݯͷૢ࡞ e.g. How to use shared resources between Actors? I think shared is an actor.

Slide 41

Slide 41 text

͋ͱͰ΍Δ࡞ઓ... μϝͩͬͨ ࣗ෼ͷ౎߹ͷྑ͍࣌ʹಡΈɺॲཧ͠ɺॻ͘ ΈΜͳ͕ͦ͏Ͱ͖Δʹ͸Ͳ͏͢Δ͔ʁ 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?

Slide 42

Slide 42 text

ͦ͏͍͏ঢ়گ͕ѱ͍ શͯͷΞΫλʔ͕୭ʹ΋ґଘ͠ͳ͍΂͖ʁ ΋͔ͯ͠͠αϒϧʔνϯͰ͍͍ʁ ͦΕͳΒΞΫλʔͷҙٛ͸... 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?

Slide 43

Slide 43 text

ͦ͏͍͏ঢ়گ͕ѱ͍ ਖ਼͘͠ॻ͚͹͏·͍͘͘ͷʹʂ ͍͍ͨͯͦ͏ ʂ - write it the right way, and it will work fine! -- This applies to usually everything

Slide 44

Slide 44 text

ͦ͏͍͏ঢ়گ͕ѱ͍ ݁Ռʹڵຯ͕ͳ͍ϒϩʔυΩϟετܥ޲͖ʁ It may work if you only do broadcasting.

Slide 45

Slide 45 text

ͦ͏͍͏ঢ়گΛड͚ೖΕΔ ΞΫλʔ͸Ϟσϧ / ےτϨ / ࢥߟ࣮ݧ Ή͠Ζঢ়گΛड͚ೖΕΑ͏ʂ Accept these situations - Actor is a model and a thought experiment -- Accept these difficult situations

Slide 46

Slide 46 text

͜͏ͨ͠ΒͲ͏ͩΖ͏ ࣗ෼͸ΈΜͳͷ౎߹ʹ߹ΘͤΔɺͱఘΊΔ ࢓ࣄͷ్தͰ΋Ͱ͖Δ͚͖ͩͭ͋͏ My suggestions: - Each actor waits and serves others first, even if you have any process left

Slide 47

Slide 47 text

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

Slide 48

Slide 48 text

͋͋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

Slide 49

Slide 49 text

్தܦաΛϝϞ͢ΔҨݴ࡞ઓ 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

Slide 50

Slide 50 text

ॲཧͷྲྀΕΛࣗવʹॻ͚ͳ͍ ίϯςΩετΛཅʹѻΘͳ͖ΌͳΒͳ͍ ॲཧΛࣗવͳྲྀΕͱͯ͠ॻ͖ʹ͍͘ 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)

Slide 51

Slide 51 text

ෳ਺ͷίϯςΩετ͕͋ͬͨ ࣗ෼͚͕ͩσʔλΛૢ࡞͢Δͷ͕҆શͷࠜڌ ͍·͸ෳ਺ͷίϯςΩετ͕ڞ༗͢Δ There were contexts - Specifying who handles data is important for safety - But now they are handled in some contexts

Slide 52

Slide 52 text

Fiberͷ࢖͍ํʹࣅͯΔʁ ϞϊεϨουͰෳ਺ͷίϯςΩετ ໌ࣔతͳίϯςΩετ੾Γସ͑ ಉ͡ऑ఺͕͋Δ Similar to Fiber? - Some contexts in a single thread - Explicit context switch - Same weak point here

Slide 53

Slide 53 text

ࢭ·Δ ϒϩοΫ͢Δॲཧ͕͋ͬͨΒશ෦ࢭ·Δ ϒϩοΫͯ͠΋શମ͸ಈ͔͍ͨ͠ ͦ͜ͰϚϧνεϨουͰ͢Αʂ ʢͦ΋ͦ΋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

Slide 54

Slide 54 text

͓͢͢Ί γεςϜશମ͸ΞΫλʔϞσϧͰߟ͑Δ ΞΫλʔͷத਎͸ϚϧνεϨου Recomended way - Think about a whole system using Actor Model - In this context, Actor is multi thread

Slide 55

Slide 55 text

͠͹Β͓͘଴͍ͪͩ͘͞ ✓ ΞΫλʔ͓͞Β͍ͨ͠ ✓ ͓͢͢Ίͨ͠ ✓ 'JCFSωλ

Slide 56

Slide 56 text

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

Slide 57

Slide 57 text

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

Slide 58

Slide 58 text

Ҏ্ʂ [event, fd]ͱϝιουΛ݁ͼ͚ͭΔ͚ͩ That's all! - That's the point of this framework

Slide 59

Slide 59 text

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.

Slide 60

Slide 60 text

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

Slide 61

Slide 61 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 62

Slide 62 text

readͷ಺ଆͷ_read͕ϛι Θ͔Γʹ͍͚͘Ͳ͕͜͜Πέϝϯ The _read insight head is the point - seems difficult, but hang in there.

Slide 63

Slide 63 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 64

Slide 64 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 Method object

Slide 65

Slide 65 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 back to Bartender

Slide 66

Slide 66 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 Unregister callback

Slide 67

Slide 67 text

dRubyϓϩτίϧ ࣮ݧ༻ΫϥΠΞϯτॻ͘ͷ͕໘౗ dRubyͷϓϩτίϧΛ࿩ͤΔαʔόΛॻ͜͏ Writing a client for experiment is tough So let's write a server that understands dRuby protocol

Slide 68

Slide 68 text

dRubyϓϩτίϧ ಈ͍ͨʂ͕͢͞ࢲʂ I did it! It works!

Slide 69

Slide 69 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 not important

Slide 70

Slide 70 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 not important

Slide 71

Slide 71 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し まくる Don't care about I/O blocking and context switch Just read it sequentially

Slide 72

Slide 72 text

BartenderͰͷFiberͷ࢖͍ํ I/OͷϒϩοΫͷࡍʹ࣮ߦݖΛख์͢ ϑϨʔϜϫʔΫ͕׬ྃΛଊ͑ͯ࠶։͢Δ - Fiber.yield when I/O block happens - The framework catches its finish and then resumes the fiber

Slide 73

Slide 73 text

ղܾ͠ͳ͔ͬͨ͜ͱ ͦͷϝιου͸௕͍ॲཧΛ͢Δͷʁ ஌Δํ๏͕ͳ͍ Θ͔ͬͨͱ͜ΖͰͲ͏͍͍͔ͯ͠Θ͔Βͳ͍ εϨουͷํ͕Ϛγ Things not solved yet - Halt when calling the method that blocks - Thread is relatively better

Slide 74

Slide 74 text

͠͹Β͓͘଴͍ͪͩ͘͞ ✓ #BSUFOEFSࣗຫ ✓ ΤʔςϧΛ࡞Ζ͏

Slide 75

Slide 75 text

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

Slide 76

Slide 76 text

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

Slide 77

Slide 77 text

ࣗ෼༻Queue

Slide 78

Slide 78 text

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

Slide 79

Slide 79 text

ॻ͍͚ͨͲ ࢖Θͳ͔ͬͨʂ ͳΜͰ΋௚ྻԽ͍ͨ͠ਓ޲͚ I wrote, but not used. It's just for those who like to serialize

Slide 80

Slide 80 text

தԝूݖܕ Rinda::TupleSpace Centralized structure

Slide 81

Slide 81 text

தԝूݖܕ Centralized structure

Slide 82

Slide 82 text

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])

Slide 83

Slide 83 text

·͋ಈ͘ dRubyͱ૊Έ߹ΘͤΕ͹ϓϩηεؒ΋ಈ͘Α Α͘࢖ͬͯΔ Yes, it works. - You can run it between processes / machines by using dRuby - I use it, frequently

Slide 84

Slide 84 text

ΤʔςϧΛॻ͍ͯؾ͍ͮͨ ΞΫλʔͱΤʔςϧͷؔ܎΋ΞΫλʔʁ Ϟσϧͱͯ͠ͷΞΫλʔ͸Ͳ͜ʹͰ΋͋Δͷ Ͱ͸ʂ As you may notice when listening to my talk, the relationship between Actor and Ether may be Actor Model, too

Slide 85

Slide 85 text

·ͱΊ Ϟσϧͱͯ͠ͷΞΫλʔΛ͓͞Β͍ ΑΓྑ͍εϨου͡Όͳ͍ؾ෼Λڞ༗ Ͱ͖ͨʁ Summary - Recap what Actor Model is - Feel like it's not just a better Thread, is it?

Slide 86

Slide 86 text

ӳ༁͋Γ͕ͱ u @yasulab @akira_nise @tenderlove