Slide 1

Slide 1 text

͠͹Β͓͘଴͍ͪͩ͘͞ ✓ ͝ཡͷεϙϯαʔͷఏڙ ʹΑΓ͓ૹΓ͠·͢

Slide 2

Slide 2 text

slide sponsors ְאַせ〢㾊3VCZ⠓陽ח⿫⸇׃׋ְ㖑⯋孖זךד!JXBEPO 䎢䃊ד׮044(BUF׃׋ְ!LUPV E3VCZח״׷ⴓ侔٥8FCفؚٗٓىؚٝ ؔ٦ي爡F#PPL4UPSF IUUQ FTUPSFPINTIBDPKQUJUMFT1!IJTBTIJN !N@TFLJךSF⿾䗁Ꟛ涪׾⿾䗁㷕统׃זָ׵⿾䗁Ꟛ涪חزٓ؎׃גְת ׅ!BXB[FLJ ⚅歲剑㣐.BTUPEPOչ1BXPPպכ3VCZך⸂ד麊欽׃גתׅ!QJYJW 〴괏׾⛦׶馉ִ䎢䃊ח⛦׶鴥׿׌涺圫ծ➙䎃׮N@TFLJ眍׾ֶ嚂׃׫ֻ׌ׁ ְ剑鵚չ،صًך鋅׵׸倯պהְֲず➂钞׾⠓爡ד⡲׏גתׅךד׉ ׍׵׮״׹׃ֻדׅկ!UTVCPJ ה׍ֺךٖه٦زֶ嚂׃׫חTNBMSVCZֹֹ׋ַ׏׋!WFTUJHF@

Slide 3

Slide 3 text

How to write synchronization mechanisms for Fiber [email protected] Cookpad, Thank you for paying the travel expenses

Slide 4

Slide 4 text

How to write synchronization mechanisms for Fiber [email protected] Special thanks to @_sasn for translation

Slide 5

Slide 5 text

@m_seki 衼⡲ 3VCZ؝ىحة &3# E3VCZ 3JOEB - Ruby committer - Author of ERB, dRuby, Rinda

Slide 6

Slide 6 text

2005 - ·ͩॳ࡮Γങ͑·͢ dRuby ʹΑΔ ؔকढ़ஶ ෼ࢄ ɾ Web ϓϩάϥϛϯά First printing from 2005 (Still available)

Slide 7

Slide 7 text

2012 (-2014 ઈ൛) Publication from 2012 (Become out of print in 2014)

Slide 8

Slide 8 text

2017 re-published on the web Re-published it on the web. CC by SA

Slide 9

Slide 9 text

Agenda 'JCFSךֶׁ׵ְ 'JCFSⰅꟌ &OVNFSBUPS 4ZODISPOJ[F .VMUJQMFYFS Agenda - Recap: Fiber - Introduction of Fiber

Slide 10

Slide 10 text

Fiberͷ͓͞Β͍ 1SPDFTT 5ISFBE 'JCFS Recap: Fiber

Slide 11

Slide 11 text

Process ↔ Thread ↔ Fiber 1SPDFTT ًٌٔכⰟ剣׃׋ְ׿׌ 5ISFBE ؝ٝذؗأزأ؎حثכ荈ⴓדװ׷ 'JCFS - Process -- Want to share memories! --- Thread ---- Do context switch by myself! ----- Fiber

Slide 12

Slide 12 text

Process ⥂隊ׁ׸׋ًٌٔ瑞꟦ فٔؒٝفذ؍ـז؝ٝذؗأزأ؎حث 猘חה׏גך䤫׸ Protected memory space preemptive task switch my dreams

Slide 13

Slide 13 text

Before Process فٗإأז׿גזַ׏׋ ,FZ׾《׶ח遤ֻ ⯓遤Ⰵ⸂זח׉׸ https://www.youtube.com/watch?v=TOnS97C-RGQ

Slide 14

Slide 14 text

Before Process (80s) 04ז׿גזַ׏׋ 1$♧〴ָفٗإأ♧א Before Process (80s) - There weren't any OS's - 1 process, 1 computer

Slide 15

Slide 15 text

ϓϩηε΁ͷಌΕ ״ֻ׻ַ׵זְֽו铣׿ד׋ ֿ׿ז⚅歲ָ֮׷ךַ A Craving for Processes - Didn't get it much, but I used to read it - Didn't know such a world

Slide 16

Slide 16 text

Before Process (90s) ⥂隊ׁ׸זְًٌٔ ⼿锃㘗وٕثةأؙ ظٝفٔؒٝفذ؍ـ ֿ׸'JCFSׄׯ׿ - no memory protection - Cooperative multitasking -- non preemptive -- Is this a ... Fiber?

Slide 17

Slide 17 text

࣮ࡍͷγεςϜ 醱侧ךفٗإأה׉׸׵ָⵃ欽ׅ׷项彁 ر٦ةד圓䧭ׁ׸׷ ꥫꨄׁ׸׋ًٌٔ瑞꟦׾馄ִ׷䗳銲ָ֮׷ فٗإأ׌ֽꥫꨄ׃ג׮穠㽷כ The Actual System - Assembled by multiple process and the resources that are used by them - Needs to jump out of the isolated memory space - Isolating processes is one thing, but for the others...

Slide 18

Slide 18 text

Processes فٗإأ׌ֽד㸣穠׃זְ 㢩鿇הךꟼ׻׶ ワ鴟鄲縧 ؿ؋؎ٕ ➭ךفٗإأ - They don't work alone - Works with -- devices, storage, other processes

Slide 19

Slide 19 text

ProcessͰॻ͘ͱ͖ͷؾ࣋ͪ קַךفٗإأהוֲחַ׃גⰟ剣׃״ֲ ׭׿וְֻֽׁו How you feel when you are using process - Try to share with other processes -- Even though it's a pain in the neck

Slide 20

Slide 20 text

ProcessͰॻ͘ͱ͖ͷؾ࣋ͪ Skip!

Slide 21

Slide 21 text

IPC͸ΊΜͲ͍͘͞ QJQF 4ZTUFN7*1$ TPDLFU ׭׿וֲ׌٦ IPCs are a pain in the neck too - Such a drag

Slide 22

Slide 22 text

Thread ًٌٔ瑞꟦׾Ⱏ剣ׅ׷⸋⻉晛فٗإأ فٔؒٝفذ؍ـז؝ٝذؗأزأ؎حث ⸋⻉ה䒷ֹ䳔ִח鯪ꆀ 㢳ֻך➂חכفٗإأך倯ְְָה䙼ֲ degraded version of process that shares memory space - The system automatically switches to Thread - Bad copy, but lightweight To most people, processes are probably better

Slide 23

Slide 23 text

ThreadͰॻ͘ͱ͖ͷؾ࣋ͪ קַךأٖحسךًٌٔ׾鍗׵זְ״ֲח ׮ךׅ׀ֻ孡׾אֽ׷ 孡׾䫙ֻה鍗׏גְ׷ 鍗׏ג׮㣐♱㣗זהֿ׹׌ֽ׾鍗׷ What it feels like to write Threads Try best to be very careful not to change memories of other threads - Tend to change it whenever you lose focus - Only change the places that are okay to change

Slide 24

Slide 24 text

Threadʹඞཁͳၗຫ͞ չ⥯ֻ׵ְחז׷ה04ח걾׵זֻג׮㸜Ⰻ ח⸬桦葺ֻ剅ֽ׷״պ ה鎉ִ׷➂ך׋׭ך娀㐻 04ךؔ٦غ٦قحسָ孡חז׷➂פ Attitude when using Threads "Secure and efficient coding without OS? No sweat." - threads will be a great advantage for you - for coders who have concerns about OS overheads

Slide 25

Slide 25 text

Fiber ظٝفٔؒٝفذ؍ـז⸋⻉晛5ISFBE و؎ؙٗأٖحس 5ISFBEⰻח醱侧ך؝ٝذؗأزָ֮׷ ⴽךⳢ椚ך鷿⚥פأ؎حثׅ׷ קה׿וך➂חכ5ISFBEך倯ְְָה䙼ֲ A non-preemptive degraded version of Thread - Micro thread - Has multiple context in one Thread - Switches during other jobs To most people, Threads are probably better

Slide 26

Slide 26 text

Fiberʹඞཁͳࣗ৴ չ⥯ֻ׵ְחז׷ה3VCZ⚛׫חֲתְأ؛ آُ٦ָٓ剅ֽ׷״պ Attitude when using Fibers "Coding a scheduler that's as good as Ruby? Piece of cake."

Slide 27

Slide 27 text

FiberͰॻ͘ͱ͖ͷؾ࣋ͪ ֲתְ؝ٝذؗأزأ؎حثך⽃⡘׾鋅א ֽ״ֲ ـٗحׇׁؙזְ״ֲחׅ׷חכ ׬׃׹'JCFS׾⢪ֲֿהָ湡涸 Attitude when using Threads "Secure and efficient coding without OS? No sweat." - threads will be a great advantage for you - for coders who have concerns about OS overheads

Slide 28

Slide 28 text

Process ↔ Thread ↔ Fiber 1SPDFTT ًٌٔכⰟ剣׃׋ְ׿׌ 5ISFBE ؝ٝذؗأزأ؎حثכ荈ⴓדװ׷ 'JCFS - Process -- Want to share memory! --- Thread ---- Do context switch by myself! ----- Fiber

Slide 29

Slide 29 text

Process ↔ Thread ↔ Fiber 'JCFS 荈⹛涸חأ؎حث׃ג״ 5ISFBE ًٌٔ⥂隊׃גֻ׸זְה㔭׷׿׌ 1SPDFTT ----- Fiber ---- Why won't it switch automatically? --- Thread -- Can't code if it doesn't protect memory! - Process

Slide 30

Slide 30 text

͠͹Β͓͘଴͍ͪͩ͘͞ ✓ ෼͘Β͍͔ͳ ✓ 1SPDFTT 5ISFBE 'JCFS ✓ ࣍͸'JCFSΛקΊΔΑʂ please wait for a moment - Done: Process, Thread, and Fiber

Slide 31

Slide 31 text

ͳͥFiberͷ࿩Λ͢Δͷ͔ 'JCFS⢪׏׋ؿٖ٦يٙ٦ָؙׅ׀ְ׵׃ְ ה耀ְ׋ ׅ׀ְ׋ְפ׿ ׅ׀ְְֻ Why Fiber? Fiber used frameworks are cool - from what I heard -- is it hard to do? -- is it really good?

Slide 32

Slide 32 text

ͳͥFiberͷ࿩Λ͢Δͷ͔ ٙةءع9ד(6*הTPDLFUفؚٗٓىؚٝ ָثّحزرٕؗ ךדծ荈ⴓד׮剅ְג׫׋ֻז׏׋ أٖحسד醱侧ךفٗإأה鸐⥋ׅ ׷׮ך I can socket program with x11 and GUI a little. - So, I decided that I'd like to use it myself -- Something that communicates with multiple processes with one Thread

Slide 33

Slide 33 text

ͳͥFiberͷ࿩Λ͢Δͷ͔ ✮䟝דכ5ISFBE״׶׮ꨇ׃ְה䙼׏׋׿׌ ֽו׉ך鸐׶ד׃׋ךדծ׫זׁ׿ח׮ֶ ׅ׉ⴓֽ׃׋ְ I suspected that it would be harder than Threads It was. Let me share my experiences with you.

Slide 34

Slide 34 text

Fiberೖ໳ 'JCPOBDDJ&OVNFSBUPS 3EW4J[FE2VFVF DIBOOFM .VMUJQMFYFS Fiber 101

Slide 35

Slide 35 text

࠷ॳͷςʔϚ &OVNFSBUPSך״ֲז圓鸡ךفؚٗٓي׾ 铣׫זָ׵ծ'JCFSך"1*׾㷕ןתׅ 'JCFSד剅ֹ湫ׅ &OVNFSUPSד剅ֹ湫ׅ First topic We will use an Enumerator like structure to learn Fiber API - Rewrite with Fiber - Rewrite with Enumerator

Slide 36

Slide 36 text

Α͋͘ΔFibonacci ٕ٦فד剅ֻה知⽃ [0, 1] [1, 1] [2, 2] [3, 3] [4, 5] [5, 8] [6, 13] [7, 21] [8, 34] [9, 55] Plain Fibonacci - Easy to write with Loop def fibonacci(n) a, b = 1, 1 n.times do |i| p [i, a] a, b = b, a + b end end fibonacci(10)

Slide 37

Slide 37 text

FiberͰॻ͖௚͢ ֿ׸׾⢪׏ג"1*׾铡僇׃תׅ fib = Fiber.new do a, b = 1, 1 while true Fiber.yield(a) a, b = b, a + b end end 10.times do |n| p [n, fib.resume] end def fibonacci(n) a, b = 1, 1 n.times do |i| p [i, a] a, b = b, a + b end end fibonacci(10) Rewrite with Fiber - Explain API using this

Slide 38

Slide 38 text

API 'JCFSOFX 'JCFSSFTVNF 'JCFSZJFME

Slide 39

Slide 39 text

Fiber.new ⴽ'JCFSדװ׶׋ְⳢ椚׾ـٗحؙד床ׅ ת׌ـٗحؙך؝٦سח鹌׫תׇ׿ fib = Fiber.new do a, b = 1, 1 while true Fiber.yield(a) a, b = b, a + b end end 10.times do |n| p [n, fib.resume] end Fiber.new - Pass value with another Fiber to do a different job - The block code will not run yet.

Slide 40

Slide 40 text

Fiber#resume 'JCFSח؝ٝذؗأز׾ⴖ׶剏ִ׷ fib = Fiber.new do a, b = 1, 1 while true Fiber.yield(a) a, b = b, a + b end end 10.times do |n| p [n, fib.resume] end Switch context to the Fiber

Slide 41

Slide 41 text

Fiber.yield SFTVNF׃׋'JCFSחⴖ׶剏ִ׷ 䒷侧ָSFTVNFך⦼חז׷ fib = Fiber.new do a, b = 1, 1 while true Fiber.yield(a) a, b = b, a + b end end 10.times do |n| p [n, fib.resume] end Switch to fiber.resume The argument becomes the value of the fiber

Slide 42

Slide 42 text

resume, again ✳䏝湡⟃꣬ךSFTVNFכZJFMEַ׵ⱄꟚׅ׷ fib = Fiber.new do a, b = 1, 1 while true Fiber.yield(a) a, b = b, a + b end end 10.times do |n| p [n, fib.resume] end resume, again From the second time on, resume restarts from yield

Slide 43

Slide 43 text

resumeͷߦ͖ઌ 'JCFS׾OFX׃׋׌ֽדכ㹋遤ׁ׸זְ SFTVNFד'JCFSח؝ٝذؗأز׾獳ׅ ♧䏝湡כ⯓걧פ ✳䏝湡⟃꣬כ'JCFSZJFME׃׋הֿ׹פ ֿ׸כ⡦䏝湡ךSFTVNFַז Where resume jumps to Would not execute just by Fiber new Pass the value to Fiber by resume -- Back to the top on the first round -- Back to Fiber.yield from the second round on --- Which round am I on...?

Slide 44

Slide 44 text

APIΛઆ໌ͨ͠ SFTVNFהZJFMEך嚊䙀ָה׏אֹחְֻ 荈歋ֺׅגוֲ׃גְְַ׻ַ׵זְ Explained the API -The concept of resume and yield is hard to grep -Don't know what to do, there are so many things we can do with it

Slide 45

Slide 45 text

EnumeratorͰॻ͖௚͢ ׉׏ֻ׶ fib = Fiber.new do a, b = 1, 1 while true Fiber.yield(a) a, b = b, a + b end end 10.times do |n| p [n, fib.resume] end def fibonacci a, b = 1, 1 while true yield(a) a, b = b, a + b end end fib = to_enum(:fibonacci) 10.times do |n| p [n, fib.next] end Rewrite with Enumerator - Nearly identical

Slide 46

Slide 46 text

Enumerator 単׾⡲׷ֿהד罋ִװֻׅז׷ ֶׅׅ׭ ❌ 'JCFSךꨇ׃ׁח䩧׍⯘אהְֲ䩛䘔ִ ָזְ Enumerator - Easier to understand when put in a frame - Recommended ❌ Can't really get the feel of overcoming the difficulties of Fiber

Slide 47

Slide 47 text

͠͹Β͓͘଴͍ͪͩ͘͞ ✓ &OVNFSBUPSͰ"1*Λઆ໌ ✓ ೉ָ͕͠͞͠Ίͳ͍ ✓ ࣍͸3EW please wait for a moment - Done: Explained the API
 - Next: Synchronizaition

Slide 48

Slide 48 text

࣍ͷςʔϚ ず劍䖉׍さ׻ׇ Next topic - Synchronization

Slide 49

Slide 49 text

QueueΛհͨ͠ڠௐ 2VFVF׾➜׃ג醱侧ך5ISFBEָ鸬䵿ׅ׷ ׉׸׊׸ך5ISFBEכֶ✼ְ׾濼׵זְ 欰欵罏ծ嶊顤罏כ醱侧ְג׮⹛ֻ q = SizedQueue.new(1) Thread.new do 10.times do |n| sleep(rand) q.push(n) p [:push, n] end end Thread.new do 10.times do |n| sleep(rand) p [:pop, q.pop] end end.join Sync with Queue - Multiple Threads synchronize through Queue - Each Thread does not know anything about other Threads - Works with multiple producers and consumers

Slide 50

Slide 50 text

͜ΕͷFiber൛ 3EW׾➜׃ג醱侧ך'JCFSָ鸬䵿ׅ׷ SFOEF[WPVT 䖉׍さ׻ׇ rdv = Rdv.new Fiber.new do 10.times do |n| rdv.push(n) p [:push, n] end end.resume Fiber.new do 10.times do |n| p [:pop, rdv.pop] end end.resume Fiber version - Multiple Fibers work together through Rdv - rendez-vous

Slide 51

Slide 51 text

rendez-vous ⚓ rendez-vous

Slide 52

Slide 52 text

ड͚औΔଆ͕଴ͭ৔߹ ⚓ rendez-vous When the consumer waits for the producer rendezvous

Slide 53

Slide 53 text

͜͏͍͏৔߹΋͋Δ ⚓ rendez-vous This might happen

Slide 54

Slide 54 text

Rdvͷ࣮૷ JOJUJBMJ[F QVTI QPQ def initialize @reader = [] @writer = [] end def push(it) if @reader.empty? @writer << [it, Fiber.current] return Fiber.yield end @reader.shift.resume(it) end def pop if @writer.empty? @reader << Fiber.current return Fiber.yield end value, fiber = @writer.shift fiber.resume return value end Implementation of Rdv

Slide 55

Slide 55 text

࠷ۙ޷͖ͳΠσΟΦϜ וֲװ׵ֿ׸׌ֽדֲתֻ剅ֽ׉ֲ ה׶ִ֮׆SFTVNF 遤ֹ鑥ת׏׋׵ZJFME My recent favorite idiom Feeling that it will go smoothly with these - just use resume - yield when you're stuck

Slide 56

Slide 56 text

ͱΓ͋͑ͣresume 'JCFSOFX׃׋׵ּׅSFTVNFׅ׷ 5ISFBEOFXך״ֲחּׅ⹛ֹ⳿ׅ 剑ⴱךSFTVNFך暴ⴽז⹛ֹ׾罋ִזֻ ג״ְ Just use resume for now - Resume right after Fiber.new -- Works right away, just like Thread.new --- Don't have to think about the special behavior on the first round

Slide 57

Slide 57 text

ߦ͖٧·ͬͨΒyield װ׸׷ֿהָ֮׷꟦כדֹ׷׌ֽװ׷ װ׸׷ֿהָזֻז׏׋׵ZJFME 䖉א湱䩛ח㼎׃גծ荈ⴓ 'JCFSDVSSFOU ׾鋙ִג׮׵ֲ Yield when you're stuck - Do as much as it can while it can do it - Yield when it has nothing to do -- Let the partner know about yourself (alias fiber.current)

Slide 58

Slide 58 text

initialize !SFBEFSכQPQ䖉׍ծ!XSJUFSכQVTI䖉׍ ך'JCFS׾ًٌׅ׷ def initialize @reader = [] @writer = [] end def push(it) if @reader.empty? @writer << [it, Fiber.current] return Fiber.yield end @reader.shift.resume(it) end def pop if @writer.empty? @reader << Fiber.current return Fiber.yield end value, fiber = @writer.shift fiber.resume return value end @reader holds fibers waiting for pop @writer holds fibers waiting for push

Slide 59

Slide 59 text

push !SFBEFSְָזְהֹծ荈ⴓ׾ًٌ׃ג䖉 א ZJFME !SFBEFSְָ׷הֹծ饯ֿׅ SFTVNF def initialize @reader = [] @writer = [] end def push(it) if @reader.empty? @writer << [it, Fiber.current] return Fiber.yield end @reader.shift.resume(it) end def pop if @writer.empty? @reader << Fiber.current return Fiber.yield end value, fiber = @writer.shift fiber.resume return value end - When there is no @reader, it records itself and wait (yield) - Resume when @reader is present (resume)

Slide 60

Slide 60 text

@reader͕͍ͳ͍ ر٦ةה'JCFSDVSSFOU׾ًٌ׃גZJFME def initialize @reader = [] @writer = [] end def push(it) if @reader.empty? @writer << [it, Fiber.current] return Fiber.yield end @reader.shift.resume(it) end def pop if @writer.empty? @reader << Fiber.current return Fiber.yield end value, fiber = @writer.shift fiber.resume return value end When @reader is not there - Records the data and Fiber.current, then yield

Slide 61

Slide 61 text

@reader͕͍Δ !SFBEFS׾♧אSFTVNFׅ׷ QPQד䖉׏גְ׋'JCFSָⱄꟚׅ׷ def initialize @reader = [] @writer = [] end def push(it) if @reader.empty? @writer << [it, Fiber.current] return Fiber.yield end @reader.shift.resume(it) end def pop if @writer.empty? @reader << Fiber.current return Fiber.yield end value, fiber = @writer.shift fiber.resume return value end @reader is present - Resume one @reader -- Fiber that was waiting for the pop resumes

Slide 62

Slide 62 text

pop !XSJUFSְָזְהֹծ荈ⴓ׾ًٌ׃ג䖉 א ZJFME !XSJUFSְָ׷הֹծ饯ֿׅ SFTVNF ׉׃גر٦ة׾鵤ׅ def initialize @reader = [] @writer = [] end def push(it) if @reader.empty? @writer << [it, Fiber.current] return Fiber.yield end @reader.shift.resume(it) end def pop if @writer.empty? @reader << Fiber.current return Fiber.yield end value, fiber = @writer.shift fiber.resume return value end When there is no @writer, it records itself and waits (yield) - When @writer is present, it resumes (resume) -- and returns data Skip!

Slide 63

Slide 63 text

@writer͕͍ͳ͍ 'JCFSDVSSFOU׾ًٌ׃גZJFME def initialize @reader = [] @writer = [] end def push(it) if @reader.empty? @writer << [it, Fiber.current] return Fiber.yield end @reader.shift.resume(it) end def pop if @writer.empty? @reader << Fiber.current return Fiber.yield end value, fiber = @writer.shift fiber.resume return value end @writer is gone Record Fiber.current and yield Skip!

Slide 64

Slide 64 text

@writer͕͍Δ !XSJUFS׾♧אSFTVNFׅ׷ QVTIד䖉׏גְ׋'JCFSָⱄꟚׅ׷ ַًٌ׵ر٦ة׾鵤ׅ def initialize @reader = [] @writer = [] end def push(it) if @reader.empty? @writer << [it, Fiber.current] return Fiber.yield end @reader.shift.resume(it) end def pop if @writer.empty? @reader << Fiber.current return Fiber.yield end value, fiber = @writer.shift fiber.resume return value end @writer is present - Resume one @writer -- a Fiber that was waiting for push resumes - Returns data value from the note Skip!

Slide 65

Slide 65 text

ݕࠪதͷഉଞ੍ޚ 'JCFSדכ勴⟝嗚叨ך䱖➭ⵖ䖴ָ♶銲 5ISFBEדכ⽬ꤹ def initialize @reader = [] @writer = [] end def push(it) if @reader.empty? @writer << [it, Fiber.current] return Fiber.yield end @reader.shift.resume(it) end def pop if @writer.empty? @reader << Fiber.current return Fiber.yield end value, fiber = @writer.shift fiber.resume return value end Exclusive control while inspecting - With Fiber, there is no need for exclusive control - Very risky on Threads!!

Slide 66

Slide 66 text

Threadͱͷҧ͍ 5ISFBEדכ嗚叨׃גְ׷꟦ח׮؝ٝذؗأ زأ؎حثׅ׷ .POJUPSהַ䗳銲 䙳ֻגسؗسׅؗ׷ Difference from Threads - Thread context switches during the inspection -- needs monitoring -- nerve-racking

Slide 67

Slide 67 text

͏༷͘͝ࢠ rdv = Rdv.new Fiber.new do 10.times do |n| rdv.push(n) p [:push, n] end end.resume Fiber.new do 10.times do |n| p [:pop, rdv.pop] end end.resume How it works. Fiber.new kara-matz is summoned! Fiber.newした
 kara-matzを召喚

Slide 68

Slide 68 text

͏༷͘͝ࢠ rdv = Rdv.new Fiber.new do 10.times do |n| rdv.push(n) p [:push, n] end end.resume Fiber.new do 10.times do |n| p [:pop, rdv.pop] end end.resume kara-matz is resumed It's kara-matz's turn! kara-matzをresume
 kara-matzのターン


Slide 69

Slide 69 text

͏༷͘͝ࢠ rdv = Rdv.new Fiber.new do 10.times do |n| rdv.push(n) p [:push, n] end end.resume Fiber.new do 10.times do |n| p [:pop, rdv.pop] end end.resume kara-matz does push() There are no opponents.. Record data and himself, then yield. kara-matzのpush!
 相手がいない。
 自分とデータをメモしyield。ターン終了

Slide 70

Slide 70 text

͏༷͘͝ࢠ rdv = Rdv.new Fiber.new do 10.times do |n| rdv.push(n) p [:push, n] end end.resume Fiber.new do 10.times do |n| p [:pop, rdv.pop] end end.resume Main's turn! Fiber.new ichi-matz is summoned! メインのターン
 Fiber.new
 ichi-matzを召喚

Slide 71

Slide 71 text

͏༷͘͝ࢠ rdv = Rdv.new Fiber.new do 10.times do |n| rdv.push(n) p [:push, n] end end.resume Fiber.new do 10.times do |n| p [:pop, rdv.pop] end end.resume ichi-matz resumed It's ichi-matz's turn! ichi-matzをresume
 ichi-matzのターン


Slide 72

Slide 72 text

͏༷͘͝ࢠ rdv = Rdv.new Fiber.new do 10.times do |n| rdv.push(n) p [:push, n] end end.resume Fiber.new do 10.times do |n| p [:pop, rdv.pop] end end.resume ichi-matz does pop! ichi-matz reads the memo takes data. kara-matz resumes the finished. ichi-matzのpop!
 ichi-matzはメモを読んだ
 データを手にいれた。kara-matzをresumeしターン終了

Slide 73

Slide 73 text

͏༷͘͝ࢠ rdv = Rdv.new Fiber.new do 10.times do |n| rdv.push(n) p [:push, n] end end.resume Fiber.new do 10.times do |n| p [:pop, rdv.pop] end end.resume kara-matz does push() There are no opponents. Record data and himself, then yield. kara-matzのpush!
 相手がいない。
 自分とデータをメモしyield。ターン終了

Slide 74

Slide 74 text

͏༷͘͝ࢠ rdv = Rdv.new Fiber.new do 10.times do |n| rdv.push(n) p [:push, n] end end.resume Fiber.new do 10.times do |n| p [:pop, rdv.pop] end end.resume ichi-matzのpop!
 ichi-matzはメモを読んだ
 データを手にいれた。kara-matzをresumeしターン終了 ichi-matz does pop! ichi-matz reads the memo takes data. kara-matz resumes the finished. Skip!

Slide 75

Slide 75 text

㔐װ׶תׅ Repeat this 10 times Skip!

Slide 76

Slide 76 text

͏༷͘͝ࢠ rdv = Rdv.new Fiber.new do 10.times do |n| rdv.push(n) p [:push, n] end end.resume Fiber.new do 10.times do |n| p [:pop, rdv.pop] end end.resume ichi-matz dies. It's main's turn Main dies. ichi-matzはしんでしまった
 メインのターン
 メインはしんでしまった Skip!

Slide 77

Slide 77 text

͏͖ͦ͝͏ʂ ֲ׀ֹתׅ It might work! - and it does

Slide 78

Slide 78 text

͜͜ͷ·ͱΊ 'JCFSָず劍ׅ׷׋׭ך➬穈׫׾⡲׏׋ 猘ך㥨ֹז؎ر؍ؔي׾荈䢧׃׋ ה׶ִ֮׆SFTVNF 遤ֹ鑥ת׏׋׵ZJFME Wrapping up Made a structure of synchronizing fibers Proudly presented my favorite idiom - just use resume - yield when you're stuck

Slide 79

Slide 79 text

͜͜ͷ·ͱΊ ず劍ך勴⟝嗚叨ח䱖➭ⵖ䖴ְ׵זְ 农럀涸ח5ISFBEח㢌䳔ׁ׸׷ה㔭׷ 5ISFBE׾⢪׏גְ׋א׮׶ָ㹋כ'JCFS ׌׏׋ך倯ְְָה䙼ֲ Wrapping up We don't need exclusive control when sync-ing - Don't want it to be implicitly converted into Threads -- It's better off that it was actually Fiber when you thought you were using Threads

Slide 80

Slide 80 text

͠͹Β͓͘଴͍ͪͩ͘͞ ✓ 'JCFSͷಉظͷ࣮૷ ✓ 3EW ✓ ࣍͸ιέοτϓϩάϥϛ ϯά please wait for a moment - Done: Synchronization 
 - Next: Sockets

Slide 81

Slide 81 text

࣍ͷςʔϚ TPDLFUך؟٦غ٦فؚٗٓىؚٝ فٗز؝ٕךⳢ椚׾荈搫ח剅ֹ׋ְ׃ծ醱 侧ך䱸竲׮䪔ְ׋ְ׿׌ֽו٦ Next Topic - Socket server programming - Want to code protocol processes smartly and support multiple connections..

Slide 82

Slide 82 text

͢͢Ί͔ͨ E3VCZ؟٦غ٦ך毟⡂؝٦سד铡僇 稆劰׌ֽו⚛遤ח⹛ַזְ׮ך 5ISFBE׾欽ְג⚛遤ח⹛ֻ׮ך 5ISFBE晛׾'JCFS晛ח׃׋׮ך؎و؎ ث ׉ך何葺晛 Table of Contents: explain with dRuby server pseudo code - Coding is simple, but doesn't move in parallel - Works in parallel with Threads - Code above rewritten to use Fiber (bit awkward) -- Better version using Fiber

Slide 83

Slide 83 text

ૉ๿͚ͩͲҰ్ ⽃秪ח♧湫简ח剅ְ׋׮ך *0כـٗحؙׅ׷ֽו孡ח׃זְ ؙٓ؎،ٝز׃ַ⹛ַזְ def main_loop loop do select fds.each do |fd| call_callback end end end def on_accept c = accept loop do read_request(c) do_it write_response(c) end end Simple but not parallel - Written straight forward - Ignore I/O blocks - Only works with one client def read_n(fd, sz) ... ... end

Slide 84

Slide 84 text

Thread൛ GE׀הח5ISFBE׾饯⹛ׅ׷ ֿ׸׌ֽד⚛遤ח⹛ֻ def main_loop loop do select fds.each do |fd| call_callback end end end def on_accept c = accept Thread.new(c) do |fd| loop do read_request(fd) do_it write_response(fd) end end end Thread ver - Start a new thread on every fd - Add 2 columns and it works in parallel def read_n(fd, sz) ... ... end ௥Ճ͸͚ͩ͜͜ ௥Ճ͸͚ͩ͜͜

Slide 85

Slide 85 text

Fiber൛ ظٝفٔؒٝفذ؍ـ ׉ךתתדכ⚛遤ח⹛ַזְ def main_loop loop do select fds.each do |fd| call_callback end end end def on_accept c = accept Fiber.new do loop do read_request(c) do_it write_response(c) end end.resume end Fiber ver - non-preemptive - Not quite parallel, yet def read_n(fd, sz) ... ... end Swapped with Fiber

Slide 86

Slide 86 text

Fiber൛վ *0ָـٗحؙ׃׉ֲזהֹծֿ׏׉׶؝ٝ ذؗأز׾ⴖ׶剏ִ׷⡲䨌 ـٗحؙ괏ظٝـٗحؙ*0 def main_loop loop do select fds.each do |fd| call_callback end end end def on_accept c = accept Fiber.new do loop do read_request(c) do_it write_response(c) end end.resume end Fiber ver Revisioned - Switch context before it I/O blocks -- Blocking-style non-blocking I/O def read_n(fd, sz) ... fd.read_nonblock(sz) rescue WaitReadable Fiber.yield retry end

Slide 87

Slide 87 text

Block-ish non-block I/O ـٗحؙ׃׉ֲזהֹծ'JCFSZJFME׃ג NBJO@MPPQח׮ו׷ ؝٦ٕغحؙדSFTVNFׅ׷ def main_loop loop do select fds.each do |fd| call_callback end end end def on_accept c = accept Fiber.new do loop do read_request(c) do_it write_response(c) end end.resume end It Fiber.yields back to main_loop before it I/O blocks Resumes on call back def read_n(fd, sz) ... fd.read_nonblock(sz) rescue WaitReadable Fiber.yield retry end

Slide 88

Slide 88 text

ίʔϧόοΫͰresume ֿך׋׭ח㼭ׁזٓ؎ـٓٔ׾剅ֹת׃׋ Resumes on call back - I made a library to do this

Slide 89

Slide 89 text

Bartender GEךSFBEBCMF XSJUBCMFח㼎䘔׃׋؝٦ٕ غحָؙ剅ֽ׷׌ֽך噰㼭ךٓ؎ـٓٔ https://github.com/seki/bartender A tiny callback library that corresponds to fd readable & writable

Slide 90

Slide 90 text

Bartender::Context SFBEBCMF XSJUBCMFחז׏׋ֿהח孡בְ׋ ׵؝٦ٕغحؙ ֿ׸׾⢪׏גCMPDLJTIOPOCMPDL*0׾ Context#[]=(event, fd, callback) Πϕϯτछʢ:read, :writeʣͱfdͷ૊ʹίʔϧόοΫΛొ࿥ Bartender::Context Callbacks when readable or writeable Use this to implement block-ish non-block I/O register callbacks for the combination of event types (:read, :write) and fd

Slide 91

Slide 91 text

_read() SFBE@OPOCMPDLׅ׷կ⢽㢩ך㜥さכ SFBEBCMFחז׷ך׾䖉׏גַ׵SFUSZׅ׷ 䖉׏ג ׉ֿד䖉׏׍ׯتً ⴽך'JCFSח؝ٝذؗأزأ؎حثׅ׷ def _read(fd, sz) return fd.read_nonblock(sz) rescue IO::WaitReadable wait_readable(fd) retry end def wait_readable(fd); wait_io(:read, fd); end def wait_io(event, fd) self[event, fd] = Fiber.current.method(:resume) Fiber.yield ensure delete(event, fd) end - read_nonblock. On exception, it waits to be readable before it retries. - Waits to be what? -- We need to context switch to another fiber

Slide 92

Slide 92 text

read_nonblock ּׅ铣׭׷ر٦ةָ֮׸ל铣׿ד鵤ׅ T[劢弫ך؛٦أ׮״ֻ֮׷ ּׅח铣׭׷ر٦ةָזְ㜥さחכ⢽㢩 *08BJU3FBEBCMF def _read(fd, sz) return fd.read_nonblock(sz) rescue IO::WaitReadable wait_readable(fd) retry end def wait_readable(fd); wait_io(:read, fd); end def wait_io(event, fd) self[event, fd] = Fiber.current.method(:resume) Fiber.yield ensure delete(event, fd) end If there are any readable data, it reads and returns - There are cases when it's below sz Excepts when there is no readable data - IO::WaitReadable

Slide 93

Slide 93 text

wait_io() ؝٦ٕغحؙה׃גSFTVNF׾涫ꐮ ׉׃ג'JCFSZJFME 剑穄涸חً؎ٕٝ٦فח䨱׶TFMFDUׅ׷ SFTVNFׁ׸׋הֹSFBEBCMFחז׏ג׷ def _read(fd, sz) return fd.read_nonblock(sz) rescue IO::WaitReadable wait_readable(fd) retry end def wait_readable(fd); wait_io(:read, fd); end def wait_io(event, fd) self[event, fd] = Fiber.current.method(:resume) Fiber.yield ensure delete(event, fd) end Register resume as callback Fiber.yield - Goes back to mainloop and selects at the end readable when resumed

Slide 94

Slide 94 text

㹋ꥷך،فٔ؛٦ءّٝד铡僇׃תׅ I'll show this to you on an actual application

Slide 95

Slide 95 text

tiny_drbͷൈਮ ًحإ٦آ铣׿ד穈׫甧ג׷鿇ⴓדׅ ـٗحؙ׾孡חׇ׆⽃秪זSFBE׾⚛ץג׷ ـٗحؙׅ׷㜥さחכ农럀涸ח؝ٝذؗأ ز׾أ؎حث׃תׅ 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 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 extracted from tiny_drb - Where it constructs with the read messages - Just lining up reads, blocks are ignored - When blocked, it context switches implicitly.

Slide 96

Slide 96 text

צҧ͍ ❌ SFBEBCMFז׵ًحإ٦آ׾ּׅחⰋ鿇铣׭׷ ❌ XSJUBCMFז׵ًحإ٦آ׾ּׅחⰋ鿇剅ֽ׷ misinterpretation Can read all messages when it's readable Can write all messages when its writeable

Slide 97

Slide 97 text

ੲΑ͘ݟͨόά TFMFDU ך֮הծًحإ٦آ׾铣׿ד穈׫甧 ג׷ꟼ侧׾؝٦ٕ 鹼䒀ծꥺ㹱ָ֮׷הةأؙأ؎حثדֹ ׆ח㔿ת׷ Bugs in the good Ol' days (in C) - Call functions that read & construct messages after select() -- Cannot switch tasks when there is latency and/or incident, and freezes

Slide 98

Slide 98 text

σϞʢ͸͋Γ·ͤΜʣ 醱侧ךؙٓ؎،ٝزָ⹛ֻ圫㶨ָTBNQMFח 剅ְג֮׶תָׅ ⹛ַ׃ג׮鋅ג׻ַ׵זַ׏׋ךד (There is no) DEMO - You can see how multiple clients work in the sample.. -- But you couldn't really *see* it moving

Slide 99

Slide 99 text

tiny_drb.rb irb -r drb irb -r drb tiny_drb.rb Rdv https://github.com/seki/bartender/tree/master/sample Skip!

Slide 100

Slide 100 text

tiny_drbͷ͓΋͠Ζ͍ͱ͜Ζ CMPDLJTIOPOCMPDL*0 僇爙涸זأ؛آُ٦ָٓזְ ♧אך'JCFSָ醱侧ך➬穈׫TFMFDU겲ה 3EWהַהֲתֻ⹛ְגְ׷ Interesting stuff about tiny_drb - block-ish nonblock I/O - No written scheduler -- One Fiber is working around well with multiple nodes (select, Rdv, etc.)

Slide 101

Slide 101 text

ଞʹࢼ࡞ͨ͠΋ͷ 'JCFS晛3JOEB5VQMF4QBDF 'JCFS晛8SJDL '%׾ⵃ欽׃׋5ISFBEהך䖉׍さ׻ׇ Other prototypes - Rinda::TupleSpace - Fiber edition - WEBrick - Fiber edition - Synchronize Threads with FD Skip!

Slide 102

Slide 102 text

Threadͱͷ଴ͪ߹Θͤ 5ISFBEWBMVFׅ׷ה姺ת׏ג׃תֲ *0QJQFךDMPTF׾⢪׏ג穄✪׾鸐濼ׅ׷ class ThreadTask def initialize(*args, &block) left, @right = IO.pipe @task = Thread.new do begin block.call(*args) ensure left.close end end end def value if @right Bartender.wait_readable(@right) @right.close end @task.value ensure @right = nil end end Sync Threads with FD - Stops on Thread.value - Notifies stop with IO.pipe close Skip!

Slide 103

Slide 103 text

Multiplexerͷ·ͱΊ ⽃秪ח♧湫简ח剅ֹ׋ְWT⚛遤Ⳣ椚 5ISFBE⤑ⵃ 'JCFSד⚛遤䏝♳־׷ךꨇ׃ְ CMPDLJTIOPOCMPDL*0׾⡲׏׋ Multiplexer Wrap-up - Simple coding vs parallelism - Threads are useful - Hard to implement perfect parallel with Fiber -- made block-ish non-block I/O

Slide 104

Slide 104 text

Fiberೖ໳ͷ·ͱΊ 'JCPOBDDJ&OVNFSBUPS 3EW4J[FE2VFVF DIBOOFM .VMUJQMFYFS ꨇ׃ְ״י Fiber 101 Wrap-up - Difficult, ain't it?

Slide 105

Slide 105 text

͠͹Β͓͘଴͍ͪͩ͘͞ ✓ ࣌ؒ͋Δ͔ͳʁ ✓ ͓·͚ please wait for a moment

Slide 106

Slide 106 text

͓·͚ 'JCFSכꨇ׃ְהֿ׹ָ꬗涯ְ ➙㔐כֲתְֻ׏׋ֽו㣟侁׃׋鑧 Digression - Fiber is hard, and fun - It went well this time, but a story about it *not* working Skip?

Slide 107

Slide 107 text

ࠓճͷྫ͸ 农鎸דֹ׷ֻ׵ְ㼭ְׁ➬穈׫׌׏׋ ➬穈׫חさ׻ׇג،فٔ؛٦ءّٝ׾剅 ֽ׷ 如ך״ֲז縐׾鼘ֽ׵׸׋ This example - Was pretty small, small enough to memorize it all -- Can code & adapt according to a particular application - Didn't get stuck in the following traps:

Slide 108

Slide 108 text

᠘ 'JCFSך⚥ד鹼ְⳢ椚׾׃גـٗحؙ ㄎ׿׌⯓ד5ISFBE⡲׏גְג'JCFS&SSPS ׌׸ַךHFNךזַדְֲֲֿֿהװ׏ג ׷ַ׮ Traps: - Get blocked inside Fiber by processing something slow in it - Read some place that used a thread and FiberError - Somebody might have already done this in gem somewhere

Slide 109

Slide 109 text

ͭ·Γ ،فٔ؛٦ءّٝך⢪ֲٓ؎ـٓٔךׅ׫ ׆׫תד㹋鄲׾椚鍑׃גזְהعو׷ عو׷׏ג鋙ִגֶֽל㣐♱㣗 㹋כ'JCFSׄׯזֻג׮عو׷ The point is - that you need to understand everything about the library or you'll get stuck -- If you know that you'll get stuck, you're okay --- (Actually, it doesn't need to be Fiber to get stuck)

Slide 110

Slide 110 text

ϋϚΔྫ 'JCFS晛ך5XJUUFSךة؎يٓ؎ٝך铣׫鴥׫ ⡲׹ֲ +40/QBSTFכأزٔ٦ي׾Ⰻ鿇铣׿ד 4USJOHח׃׍ׯֲ̔تً أزٔ٦يַ׵铣׬+40/QBSTFזְ Examples of getting stuck - Making a Fiber version of Twitter timeline reading -- JSON.parse reads and puts everything into a string →Won't work - Is there JSON.parse that reads from streams?

Slide 111

Slide 111 text

ϋϚΓͦ͏ͳྫ 3%#.4ךسٓ؎غהַ 㔿ת׵זְך More examples of places to get stuck - RDBMS drivers...? -- Do they freeze?

Slide 112

Slide 112 text

͠͹Β͓͘଴͍ͪͩ͘͞ ✓ ͓ΘΓ please wait for a moment - Almost the end

Slide 113

Slide 113 text

·ͱΊ 5ISFBEכꨇ׃ְָ'JCFSכ׮׏הꨇ׃ְ 'JCFSך"1*הず劍ծ*0ך䘔欽⢽׾爙׃׋ 剑鵚㥨ֹז؎ر؍ؔي׾稱➜׃׋ Summary - Threads are hard, but Fibers are even harder - Explained Fiber API, synchronization, I/O Multiplexer application - Introduced my favorite idiom

Slide 114

Slide 114 text

Process ↔ Thread ↔ Fiber 'JCFS 荈⹛涸חأ؎حث׃ג״ 5ISFBE ًٌٔ⥂隊׃גֻ׸זְה㔭׷׿׌ 1SPDFTT ----- Fiber ---- Why won't it switch automatically? --- Thread -- Can't code if it doesn't protect memory! - Process