Slide 1

Slide 1 text

(Pฒߦॲཧύλʔϯ

Slide 2

Slide 2 text

ϞόΠϧόοΫΤϯυ େࡕࣄ຿ॴ!̍ਓ 3BJMTͱ͔/PEFͱ͔࢖ͬͯ"1*࡞ͬͯ·͢ (Pྺϲ݄

Slide 3

Slide 3 text

جૅ

Slide 4

Slide 4 text

ฒߦॲཧ͍ͨ͠ཧ༝ w $16ίΞΛෳ਺࢖͍͍ͨ w ϊϯϒϩοΩϯάͰॲཧ͍ͨ͠

Slide 5

Slide 5 text

$16ͷΫϩοΫ਺೥ද 0 750 1500 2250 3000 1980 1990 2000 2010 2020 ͋ͨ·͏ͪ ٸܹʹ৳ͼͨ

Slide 6

Slide 6 text

ίΞ ίΞ ॲཧΛ෼ׂ ฒྻ ίΞ ඵ ඵ

Slide 7

Slide 7 text

଴ͪΛղফ ฒߦ ॲཧ ॲཧ *0଴ͪ *0଴ͪ ॲཧ ॲཧ *0଴ͪ *0଴ͪ *0଴ͪ *0଴ͪ *0଴ͪ *0଴ͪ ଴ͪ࣌ؒΛͳ͘͠ ϨεϙϯεΛૣ͘͢Δ

Slide 8

Slide 8 text

$41 $PNNVOJDBUJOH4FRVFOUJBM1SPDFTTFT

Slide 9

Slide 9 text

໊લ͕ࣔ͢ͱ͓Γɺ$41͸ಠཱͨ͠ϓϩηε܈͕ϝοηʔδύογ ϯάʹΑͬͯ௨৴͢Δ͜ͱͰ૬ޓʹ΍ΓऔΓ͍ͯ͠Δ΋ͷͱͯ͠γ εςϜΛهड़͢Δɻ͔͠͠ɺ$41ͷ໊শʹؚ·ΕΔ4FRVFOUJBM ʢஞ࣍తʣͱ͍͏෦෼͸ޡղΛੜ͡ΔՄೳੑ͕͋Δɻͱ͍͏ͷ΋࠷ ۙͷ$41Ͱ͸ɺϓϩηε͸୯ͳΔஞ࣍తϓϩηε͚ͩͰͳ͘ɺΑΓ جຊతͳϓϩηε܈ͷฒྻ߹੒Ͱੜ੒͞ΕΔϓϩηε΋ؚ·ΕΔ͔ ΒͰ͋Δɻϓϩηεؒͷؔ܎΍ϓϩηε͕पғͱ௨৴͢Δํ๏͸ɺ ֤छϓϩηε୅਺ԋࢉࢠΛ࢖ͬͯද͞ΕΔɻ͜ͷΑ͏ͳ୅਺తख๏ Λ࢖͏͜ͱͰɺগ਺ͷϓϦϛςΟϒཁૉ͔Β༰қʹۃΊͯෳࡶͳϓ ϩηεΛߏஙͰ͖Δɻ 8JLJQFEJBΑΓ

Slide 10

Slide 10 text

ͳΔ΄ͲΘ͔ΒΜ

Slide 11

Slide 11 text

ฒߦॲཧͷ໰୊ɹ 1SPDFTT 1SPDFTT $POUFYU QSPHSFTT 1SPDFTTؒͷ$POUFYUͷڞ༗͕೉͍͠

Slide 12

Slide 12 text

ฒߦॲཧͷछྨ w 4IBSFE.FNPSZ w .FTTBHF1BTTJOH

Slide 13

Slide 13 text

4IBSFE.FNPSZ 5ISFBE 5ISFBE .VUFY -PDL -PDL"RVJSFE -PDL 6OMPDL -PDL"RVSJFE 6OMPDL Block

Slide 14

Slide 14 text

%FBEMPDL 5ISFBE 5ISFBE .VUFY -PDL -PDL"RVJSFE -PDL -PDL"RVSJFE .VUFY -PDL -PDL

Slide 15

Slide 15 text

.VUFY౳Λ࢖͍जΕ෺Λ৮ΔΑ͏ʹ ϝϞϦΛอޢ͠ͳ͕Β΍ΓͱΓΛߦ͏ Ұൠతʹ೉͍͠ॲཧ

Slide 16

Slide 16 text

.FTTBHF1BTTJOH 1SPDFTT 1SPDFTT ϓϩηεಉ͕࢜ϝοηʔδΛૹΓ߹ͬͯ΍ΓͱΓ͢Δ ༻ҙ͞Εͨ఻ୡखஈΛ࢖͏͜ͱʹ Αͬͯ೉͍͜͠ͱΛ ͋Δఔ౓͓·͔ͤͰ͖Δ WBS

Slide 17

Slide 17 text

%POPUDPNNVOJDBUFCZ TIBSJOHNFNPSZJOTUFBE TIBSF NFNPSZCZDPNNVOJDBUJOH

Slide 18

Slide 18 text

(Pಛ༗ͷߏจ

Slide 19

Slide 19 text

func onExit() { fmt.Println("exit!") } func main() { defer onExit() fmt.Println("end") } > go run main.go end exit! EFGFS ؔ਺ऴྃ࣌ʹ࣮ߦ͢Δؔ਺Λొ࿥͢Δ

Slide 20

Slide 20 text

func main() { arr := []int{1,2,3} for _, i := range arr { fmt.Println(i) } } > go run main.go 1 2 3 SBOHF ഑ྻ΍$IBOOFM͔Βஞ࣍తʹ஋ΛऔΓग़͢

Slide 21

Slide 21 text

ฒߦॲཧͷಓ۩ɹ

Slide 22

Slide 22 text

(PSPVUJOF ॲཧͷ࣮ߦ୯Ґ

Slide 23

Slide 23 text

ಛ௃ w εϨουͱ΄΅ಉ͡ w εϨουΑΓܰྔ w εϨουΑΓܰྔͳͷͰͨ͘͞Μ্ཱͪ͛ͯ΋ಈ࡞͢Δ w (PͷεέδϡʔϥʹΑΓ(PSPVUJOFΛෳ਺ͷεϨο υʹׂΓ౰ͯΒΕΔͨΊɺ(PSPVUJOFͰฒߦॲཧ͢Δ ͱಁաతʹ$16ίΞ͕ෳ਺࢖ΘΕΔ

Slide 24

Slide 24 text

ίετ w ͭόΠτ εϨουͷελοΫαΠ ζ͸͍͍ͩͨ.όΠτ w ੾Γସ͕͑εϨουΑΓܰྔ

Slide 25

Slide 25 text

࢖͍ํ go func() {}(); 25 HPΩʔϫʔυʹؔ਺ݺͼग़͠Ͱ (PSPVUJOFΛੜ੒͠ฒߦॲཧΛߦ͏ HPΩʔϫʔυؔ਺ݺͼग़͠

Slide 26

Slide 26 text

ཁૉ go func() {}(); 26 ಗ໊ؔ਺ +BWB4DSJQUͰ͍͏ GVODUJPO \^ ؔ਺ݺͼग़͠ɹ HPΩʔϫʔυɹ

Slide 27

Slide 27 text

࢖͍ํ func foo() { time.Sleep(1 * time.Second) fmt.Println("2") } func main() { fmt.Println("1") // go キーワードの後に関数呼び出しを行うとGoroutineが // 生成され並行に実行される go foo() fmt.Println("3") time.Sleep(2 * time.Second) } 27 > go run main.go 1 3 2

Slide 28

Slide 28 text

$IBOOFM 28 (PSPVUJOFಉ࢜ͷϝοηʔδΛதܧ͢ΔύΠϓ PL PL

Slide 29

Slide 29 text

ಛ௃ w (PSPVUJOFಉ࢜ͷ஋ͷड͚౉͠ͷͨΊͷಓ۩ w ϝοηʔδύογϯάΛ࣮ݱ͢Δಓ۩ w ૹ৴ɺड৴͕Ͱ͖Δ·ͰHPSPVUJOFΛϒϩοΫ͢Δ w #VGGFSΛࢦఆͰ͖Δ w ϑΝʔετΫϥεΦϒδΣΫτͳͷͰม਺ͱͯ͠ड͚౉ ͕͠Ͱ͖Δ 29

Slide 30

Slide 30 text

࢖͍ํ // 送信する値の型を指定しChannelを生成 ch := make(chan int) // 受信(Channelから <-演算子で取り出す) val := <- ch // 変数に代入しなくてもいい <- ch // 送信(Channelに向かって <-演算子で送信) ch <- 1 // 閉じる close(ch) 30

Slide 31

Slide 31 text

࢖͍ํ func main() { ch := make(chan int) go func() { // 送信 ch <- 1 }() // 受信 i := <-ch fmt.Println(i) } 31 > go run main.go 1

Slide 32

Slide 32 text

࢖͍ํ func main() { ch := make(chan int) go func() { // 送信 ch <- 1 }() // 受信 i := <-ch fmt.Println(i) } 32 DI

Slide 33

Slide 33 text

GPSSBOHFΛ࢖ͬͯ ഑ྻͷΑ͏ʹϧʔϓͰ͖Δ func main() { ch := make(chan int) go func() { ch <- 1 ch <- 2 close(ch) }() // Channelがcloseされるまでループする for i := range ch { fmt.Println(i) } } 33 > go run main.go 1 2

Slide 34

Slide 34 text

#VGGFSFE$IBOOFM // bufferの数を指定するとbuffer有りのChannelになる ch := make(chan int, 2) ch <- 1 ch <- 1 ch <- 1 // bufferの数を超えて書き込もうとするとブロック 34

Slide 35

Slide 35 text

DMPTF func main() { ch := make(chan int, 1) ch <- 1 close(ch) // ch <- 1 CloseされたChannelには送信できない // Closeされても読み出せる fmt.Println(<-ch) // 呼び出せる値がなくなった場合は // ゼロ値(intの場合0、stringの場合"")が返ってくる fmt.Println(<-ch) fmt.Println(<-ch) } 35 > go run main.go 1 0 0

Slide 36

Slide 36 text

4FMFDU 36 ෳ਺ͷ$IBOOFMΛಉ࣌ʹૢ࡞͢Δ

Slide 37

Slide 37 text

ಛ௃ w ෳ਺ͷ$IBOOFMΛѻ͏ͱ͖ʹ࢖͏ w ͍ͣΕ͔ͷ$IBOOFM͕ड৴ɺૹ৴Ͱ͖Δঢ়ଶʹͳΔ· ͰϒϩοΫ͢Δ w ֤DBTFͷॲཧ͕ಉ࣌ʹ૸Βͳ͍͜ͱ͕อূ͞Ε͍ͯΔ w EFGBVMU۟Λॻ͘ͱɺશͯͷ$IBOOFM͕ड৴ɺૹ৴ Ͱ͖ͳ͍৔߹ʹ࣮ߦ͞ΕΔɻ ϒϩοΫ͞Εͳ͘ͳΔ 37

Slide 38

Slide 38 text

select { case v := <-ch1: // Ch1 から受信 case <-ch2: // 受信した場合でも代入式は必須じゃない case ch3 <- 1: // 送信することも可能 default: // 全てのcaseで送受信不能な場合 } ࢖͍ํ

Slide 39

Slide 39 text

dataCh1 := make(chan int) dataCh2 := make(chan int) closeCh := make(chan struct{}) go func() { for { // selectは一度処理すると抜けてしまうのでforループで囲む fmt.Println("select start") select { case d := <-dataCh1: fmt.Println(">>> 1:", d) time.Sleep(1 * time.Second) fmt.Println("<<< 1:", d) case d := <-dataCh2: fmt.Println(">>> 2:", d) time.Sleep(1 * time.Second) fmt.Println("<<< 2:", d) case <-closeCh: fmt.Println("close") return } } }() fmt.Println("Send 1 => dataCh1") dataCh1 <- 1 fmt.Println("Send 2 => dataCh1") dataCh1 <- 2 fmt.Println("Send 1 => dataCh2") dataCh2 <- 1 fmt.Println("Send true => closeCh") closeCh <- struct{}{} > go run main.go Send 1 => dataCh1 select start >>> 1: 1 Send 2 => dataCh1 <<< 1: 1 select start >>> 1: 2 Send 1 => dataCh2 <<< 1: 2 select start >>> 2: 1 Send true => closeCh <<< 2: 1 select start close

Slide 40

Slide 40 text

TZODύοέʔδ (PͰ͸ϝοηʔδύογϯά͚ͩͰશͯΛ࿫͏ͷ͸ ݱ࣮తͰͳ͍ͱ͍͏ཧ༝Ͱ4IBSFE.FNPSZͷ πʔϧ΋༻ҙ͞Ε͍ͯ·͢ 40

Slide 41

Slide 41 text

छྨ w TZOD8BJU(SPVQ w TZOD0ODF w TZOD.VUFY 41

Slide 42

Slide 42 text

छྨ w TZOD8BJU(SPVQ w TZOD0ODF w TZOD.VUFY 42

Slide 43

Slide 43 text

ಛ௃ w ෳ਺ͷ(PSPVUJOFͷऴྃΛ଴ͭͨΊͷಓ۩ 43

Slide 44

Slide 44 text

wg := new(sync.WaitGroup) // AddでWaitする数を追加する wg.Add(1) // Done()でAddした数をデクリメント wg.Done() // Addした数が0になるまでSleep wg.Wait() ࢖͍ํ

Slide 45

Slide 45 text

func main() { wg := new(sync.WaitGroup) for i := 0; i < 10; i++ { // 待つ数を登録する。1回のループにつきGoroutineを // 1つ生成するので1を追加していく wg.Add(1) go func(i int) { // deferキーワードでこの関数を抜けるときに // wg.Done()が呼ばれるように登録する defer wg.Done() time.Sleep(1 * time.Second) fmt.Println(i) }(i) } // wg.Addで追加した数の合計数wg.Done()が呼ばれるまで待機 fmt.Println("** wait **") wg.Wait() fmt.Println("** done **") } > go run main.go ** wait ** 0 8 6 2 1 3 4 5 7 9 ** done ** ࢖͍ํ

Slide 46

Slide 46 text

ύλʔϯ 46

Slide 47

Slide 47 text

4ZOD (PSVUJOFಉ࢜ͷ଴ͪ߹Θͤ 47

Slide 48

Slide 48 text

// 終了のお知らせを伝えるためのChannel wait := make(chan struct{}) go func() { time.Sleep(1 * time.Second) // 処理が終了したらwaitに値を送信 wait <- struct{}{} }() // 値が書き込まれるまでブロック <-wait

Slide 49

Slide 49 text

'BO*O 49 ෳ਺ͷ1SPDFTT͔Β ͭͷ1SPDFTTʹू໿͢Δ

Slide 50

Slide 50 text

1SPEVDFS 1SPEVDFS $POTVNFS 50

Slide 51

Slide 51 text

func producer(out chan<- int, v int) { for i := 0; i < 10; i++ { out <- v time.Sleep(time.Duration(v) * time.Second) } } func consumer() { ch := make(chan int) go producer(ch, 1) go producer(ch, 2) // producerが送信した値を集約して出力 for i := range ch { fmt.Println(i) } }

Slide 52

Slide 52 text

'BO0VU 52 ͭͷ2VFVFΛෳ਺ͷϓϩηεͰॲཧ͢Δ

Slide 53

Slide 53 text

$POTVNFS $POTVNFS ͭͷ2VFVF͔Βෳ਺ͷϓϩηεʹ౉͢ 1SPEVDFS 53

Slide 54

Slide 54 text

func consumer(ch <-chan int, wg *sync.WaitGroup) { wg.Add(1) defer wg.Done() for i := range ch { fmt.Println(i) } } func producer(size int) { queue := make(chan int) wg := new(sync.WaitGroup) go consumer(queue, wg) go consumer(queue, wg) for i := 0; i < size; i++ { queue <- i } close(queue) wg.Wait() }

Slide 55

Slide 55 text

(FOFSBUPS ഑ྻͷ୅ΘΓʹ(PSPVUJOFͰ஋Λੜ੒͠ $IBOOFMͰૹ৴͢Δ͜ͱͰϝϞϦΛઅ໿͢Δ 55

Slide 56

Slide 56 text

func Generator(n int) chan int { ch := make(chan int) go func() { for i := 0; i < n; i++ { // 与えられた数まで順番にChannelに書き込んで行く ch <- i } close(ch) }() return ch } func main() { for i := range Generator(10000) { fmt.Printf("%d", i) } }

Slide 57

Slide 57 text

1JQFMJOF (PSPVUJOFͷग़ྗ͕ผͷ(PSPVUJOFͷೖྗʹͳͬͯΔ $IBOOFMΛ௨ͯ͠ஞ࣍తʹॲཧ͞ΕΔ 57

Slide 58

Slide 58 text

(FOFSBUPS EPVCMF QSJOUFS ΠϯΫϦϝϯτ ͨ͠஋ΛPVUʹ ॻ͖ࠐΉ JOͰड͚औͬͨ ஋Λഒͯ͠PVUʹ ॻ͖ࠐΉ JOͰड͚औͬͨ ग़ྗ͢Δ ʜ ʜ

Slide 59

Slide 59 text

func generator(n int) <-chan int { out := make(chan int) go func() { defer close(out) for i := 0; i < n; i++ { out <- i } }() return out } func double(in <-chan int) <-chan int { out := make(chan int) go func() { defer close(out) for i := range in { out <- i * 2 } }() return out } func print(in <-chan int) { for i := range in { fmt.Println(i) } } func main() { ch1 := generator(10) ch2 := double(ch1) print(ch2) } > go run main.go 0 2 4 6 8 10 12 14 16 18

Slide 60

Slide 60 text

Τϥτεςωεͷᝲ ࢀߟIUUQTUBMLTHPMBOHPSH DPODVSSFODZTMJEF ࢦఆ͞Εͨ੔਺ҎԼͷૉ਺ΛશͯٻΊΔΞϧΰϦζϜ

Slide 61

Slide 61 text

୳ࡧϦετʜ ૉ਺Ϧετ 9·Ͱͷ஋Λ୳ࡧϦετ
 ʹೖΕΔ ୳ࡧϦετʜ ૉ਺Ϧετ ୳ࡧϦετͷઌ಄Λ ૉ਺ϦετʹҠ͢ ୳ࡧϦετʜ ૉ਺Ϧετ ୳ࡧϦετ͔ΒҠͨ͠ ૉ਺ͷഒ਺Λ࡟আ͢Δ ୳ࡧϦετͷઌ಄Λ ૉ਺ϦετʹҠ͢ ୳ࡧϦετʜ ૉ਺Ϧετ Ҏ߱܁Γฦ͠ʜ

Slide 62

Slide 62 text

// Send the sequence 2, 3, 4, ... to channel 'ch'. func Generate(ch chan<- int) { for i := 2; ; i++ { ch <- i // Send 'i' to channel 'ch'. } } // Copy the values from channel 'in' to channel 'out', // removing those divisible by 'prime'. func Filter(in <-chan int, out chan<- int, prime int) { for { i := <-in // Receive value from 'in'. if i%prime != 0 { out <- i // Send 'i' to 'out'. } } } // The prime sieve: Daisy-chain Filter processes. func main() { ch := make(chan int) // Create a new channel. go Generate(ch) // Launch Generate goroutine. for i := 0; i < 10; i++ { prime := <-ch fmt.Println(prime) ch1 := make(chan int) go Filter(ch, ch1, prime) ch = ch1 } } 62

Slide 63

Slide 63 text

(FOFSBUF ૉ਺ͷ 'JMUFS ૉ਺ͷ 'JMUFS ʜ */ */ 065 ʜ ૉ਺ͷ 'JMUFS 065 */ ʜ ૉ਺͕ݟ͔ͭΔຖʹ 'JMUFS͕૿͍͑ͯ͘ ϑΟϧλ͞Εͳ͔ͬͨ ࠷ॳͷ਺͕ૉ਺ QSJNF

Slide 64

Slide 64 text

func Generate(ch chan<- int) { for i := 2; ; i++ { ch <- i // 2から順に最初のFilterに送信していきます } } 64

Slide 65

Slide 65 text

// in => 前のFilter(Generator)から数値を渡されるChannel // out => 次のFilterに数値を渡すChannel // prime => Filterに設定される素数 func Filter(in <-chan int, out chan<- int, prime int) { for { i := <-in // Filter(Generator)から数値が渡ってくる if i%prime != 0 { out <- i // 自身に渡された素数で割り切れないもの次のFilterに送る } } } 65

Slide 66

Slide 66 text

func main() { ch := make(chan int) go Generator(ch) // 素数を10個見つけるまでループ for i := 0; i < 10; i++ {
 // 待機リストの最初の数値を素数として受信 prime := <-ch fmt.Println(prime) // FilterのoutになるChannelを用意 ch1 := make(chan int) go Filter(ch, ch1, prime) // 次のフィルタのinになるChannel変数に // 今回のontのChannelを代入する ch = ch1 } } 66

Slide 67

Slide 67 text

͔ͬ͜Β͸࣌ؒ༨ͬͨ࣌༻ ଓ͖͸ϒϩάͰʂ

Slide 68

Slide 68 text

#BDLHSPVOE ॏ͍ͨॲཧΛόοΫάϥ΢ϯυͰ࣮ߦ͠ શମͷॲཧΛૣ͘͢Δ 68

Slide 69

Slide 69 text

֓ཁ w 8Ϋϩʔϥʔ w αʔόʔ͸໿NT͔͔Δ w ಺༰ͱͯ͠͸3FTQPOTFͷTUBUVTίʔυ ͷ਺ΛΧ΢ϯτͯ͠Δ͚ͩ

Slide 70

Slide 70 text

func fetch(url string) int { res, _ := http.Get(url) return res.StatusCode } func crawl(urls []string) { m := make(map[int]int) for _, url := range urls { status := fetch(url) m[status]++ } } ~/w/g/s/g/c/g/p/crawler ››› go build; time ./crawler -n 100 ./crawler -n 100 0.08s user 0.12s system 0% cpu 30.554 total ฒߦॲཧͳ͠

Slide 71

Slide 71 text

ԟ෮ʹ໿NTʹ͔͔Γ ௚ྻͰ࣮ߦ͞ΕΔͷͰϦΫΤετ਺͔͔Δ 71 'FUDI 4FSWFS ϦΫΤετ Ϩεϙϯε ໿300ms ໿300ms +α ϦΫΤετ Ϩεϙϯε

Slide 72

Slide 72 text

func fetch(url string) int { // レスポンスが返るまでブロック res, _ := http.Get(url) return res.StatusCode } ͜ͷϒϩοΫ͕ ϘτϧωοΫ

Slide 73

Slide 73 text

func crawl(urls []string) { m := make(map[int]int) // statusを受信するChannel ch := make(chan int) for _, url := range urls { go func() { // ここが並行処理 ch <- fetch(url) }() } // urlsの数だけchから読み取る for range urls { m[<-ch]++ } } ~/w/g/s/g/c/g/p/crawler ››› go build; time ./crawler -n 100⏎ ./crawler -n 100 0.04s user 0.03s system 20% cpu 0.338 total ඵ͔Β NT ·Ͱ୹ॖ

Slide 74

Slide 74 text

ϦΫΤετຖʹผͷ(PSPVUJOFͰ ॲཧ͠଴͕ͪ࣌ؒͳ͘ͳͬͨͷͰ NTͰऴྃ 74 4FSWFS 'FUDI Ϩεϙϯε ϦΫΤετ ϦΫΤετ Ϩεϙϯε

Slide 75

Slide 75 text

func crawl(urls []string) { m := make(map[int]int) // statusを受信するChannel ch := make(chan int) for _, url := range urls { go func() { // ここが並行処理 ch <- fetch(url) }() } // urlsの数だけchから読み取る for range urls { m[<-ch]++ } } ௒͑Δ͘Β͍Ͱ Τϥʔ͕සൃ .BD#PPL"JS ~/w/g/s/g/c/g/p/crawler ››› go build; time ./crawler -n 500 panic: Get http://localhost:65067: dial tcp [::1]:65067: getsockopt: connection refused

Slide 76

Slide 76 text

αʔόʔ ಉ࣌઀ଓ਺͕ଟ͗͢αʔόʔෛՙ্͕͕Γ͗ͯ͢ ઀ଓ͕Ͱ͖ͳ͘ͳ͍ͬͨͨ 76 ☓ ☓

Slide 77

Slide 77 text

4FNBQIPSF ಉ࣌ʹ࣮ߦ͢Δ(PSPVUJOFͷ਺Λ੍ݶ͢Δ 77

Slide 78

Slide 78 text

αʔόʔ (PSPVUJOFͷ਺Λ੍ݶ͠ಉ࣮࣌ߦ਺Λ཈੍ 78

Slide 79

Slide 79 text

func crawl(urls []string) { m := make(map[int]int) ch := make(chan int) // Buffered Channelの指定回数以上送信したら // 受信されるまで送信がブロックされるという特性を利用します sem := make(chan struct{}, 100) go func() { for _, url := range urls { // 100回まで送信するとブロック sem <- struct {}{} go func() { ch <- fetch(url) // 処理が終了すればChannelから受信しバッファを開けることで //同時並行数を開放していく <-sem }() } }() for range urls { m[<-ch]++ } } ~/w/g/s/g/c/g/p/crawler ››› go build; time ./crawler -n 500 ./crawler -n 500 0.17s user 0.14s system 16% cpu 1.895 total ஗͘ͳ͕ͬͨ ਖ਼ৗऴྃ͢ΔΑ͏ʹ

Slide 80

Slide 80 text

4JHOBM)BOEMFS (PͰ͸4JHOBM)BOEMFS΋$IBOOFMͰॲཧ͢Δ 80

Slide 81

Slide 81 text

// Signalを受け取るChannelを宣言 sigCh := make(chan os.Signal, 1) // 受け取るSignalを登録 signal.Notify(sigCh, syscall.SIGINT, syscall.SIGUSR1) go func() { for { select { // Signalを待ち受け case sig := <-sigCh: switch sig { case syscall.SIGINT: fmt.Println("SIGINT") os.Exit(0) case syscall.SIGUSR1: fmt.Println("SIGUSR") } } } }()

Slide 82

Slide 82 text

5JDL 5JDL Ұఆ࣌ؒຖͷॲཧ ΍5JNFPVUॲཧ΋ (PͰ͸$IBOOFMΛ࢖ͬͯߦ͍·͢ 82

Slide 83

Slide 83 text

func main() { // 3秒毎にChannelに書き込まれる tick := time.Tick(3 * time.Second) // 15秒後にChannelに書き込まれる timeout := time.After(15 * time.Second) for { select { case <-tick: fmt.Println("tick") case <-timeout: fmt.Println("timeout") return } } 83

Slide 84

Slide 84 text

1BSBMMFM8SJUF'JMF ͭͷϑΝΠϧΛෳ਺ͷ(PSVUJOFͰ ෼ׂͯ͠ॻ͖ࠐΜͰ͍͘ 84

Slide 85

Slide 85 text

QSPEVDFS ֤8PSLFS͕ ͭͷϑΝΠϧͷผͷ ։࢝Ґஔ͔Βಉ࣌ʹॻ͖ࠐΜͰ͍͘ 8PSLFS 8PSLFS 8PSLFS BB CC DD CZUFʙ CZUFʙ CZUFʙ +PC ։࢝Ґஔͱ ॻ͖ࠐΉCZUF഑ྻ

Slide 86

Slide 86 text

// ジョブ構造体 type Job struct { // 書き込むbyte配列 b []byte // 書き込むFileの開始位置 pos int64 } 86

Slide 87

Slide 87 text

type Worker struct { f *os.File // Fileポインター wg *sync.WaitGroup // 処理を待ち合わせるためのWaitGroup queue chan *Job // Jobを受信するChannel stopCh chan bool // 全てのJobが消化されWorkerを終了させたい時のChannel } // 慣例的にNew${構造体名}のメソッドを用意してインスタンスを返します func NewWorker(f *os.File, wg *sync.WaitGroup, queue chan *Job, stopCh chan bool) Worker { return Worker{ f: f, wg: wg, queue: queue, stopCh: stopCh, } } 87

Slide 88

Slide 88 text

func (w *Worker) Start() { w.wg.Add(1) go func() { defer w.wg.Done() for { select { case j := <-w.queue: // queueを受け取ったらその情報でFileに書き込み w.f.WriteAt(j.b, j.pos) case <-w.stopCh: // stopChに値が書き込まれたら関数を抜けて処理を終了します // select内は同時に走らないので最後に受け取ったqueueの処理が終わってから // このセクションが実行される事が保証される return } } }() } 88

Slide 89

Slide 89 text

func parallelWrite(lines []string) { wg := new(sync.WaitGroup) f, _ := os.Create("test.txt") defer f.Close() stopCh := make(chan bool) queue := make(chan *Job) const workers = 10 // Workerを指定回数スタートさせる for i := 0; i < workers; i++ { worker := NewWorker(f, wg, queue, stopCh) worker.Start() } pos := int64(0) for _, line := range lines { lineBytes := []byte(line + "\n") // Queueを送信。全てのWorkerが処理中なら書き込めずにここでブロック queue <- &Job{ b: lineBytes, pos: pos, } // 書き込まれたbyte数分書き込み位置をすすめる pos += int64(len(lineBytes)) } // workerを終了させるためにstopChに値を書き込んでいく for i := 0; i < workers; i++ { stopCh <- true } wg.Wait() }

Slide 90

Slide 90 text

·ͱΊ w (PͰ͸؆୯ʹฒߦॲཧ͕Ͱ͖Δಓ۩͕ἧͬ ͯΔ w (PͰ͸ܰྔͳ(PSPVUJOF͕࢖͑ΔͷͰฏ ߦ਺Λ্͛΍͍͢

Slide 91

Slide 91 text

͏͍͋ʔ͸͍͋ΓΜ͙ େࡕࣄ຿ॴͰҰॹʹಇ͍ͯ͘ΕΔਓʂ