Goroutineと channelから はじめるgo言語

214
-1

Published on

http://connpass.com/event/22536/ で発表した資料

Published in: Technology
0 Comments
5 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total Views
214
On Slideshare
0
From Embeds
0
Number of Embeds
0
Actions
Shares
0
Downloads
0
Comments
0
Likes
5
Embeds 0
No embeds

No notes for slide

Goroutineと channelから はじめるgo言語

  1. 1. Goroutineと Channelから はじめるGo言語 ver. 5 2015/11/26(木) @「最近、Go言語始めました」の会 The Go gopher was designed by Renee French. The gopher stickers was made by Takuya Ueda. Licensed under the Creative Commons 3.0 Attributions license.
  2. 2. アジェンダ ● 自己紹介 ● Goとは? ● Goroutineの基本 ● GoroutineとChannel ● 複数のChannelを扱う ● ファーストクラスオブジェクト ● 単方向のChannel ● for-selectパターン
  3. 3. 自己紹介 KLab株式会社 KLabGames事業本部 エンジニア 上田拓也 twitter: @tenntenn ■ 好きな言語 Go, JavaScript, Lua ■ 業務 モバイルオンラインゲームの開発(クライアントサイド)
  4. 4. Goとは? Googleが開発しているプログラミング言語 ■ 特徴 ● 並行プログラミング ● 豊富なライブラリ群 ● 強力でシンプルな言語設計と文法 ● クロスコンパイル/シングルバイナリ ● go tool
  5. 5. Concurrency is not Parallelism ■ ConcurrencyとParallelismは違う ● Concurrency => 並行 ● Parallelism => 並列 ■ Concurrency ● 同時にいくつかの質の異なる事を扱う ■ Parallelism ● 同時にいくつかの質の同じ事を行う by Rob Pike
  6. 6. Concurrency is not Parallelism ■ Concurrency ■ Parallelism 本を運ぶ 本を燃やす 台車を運ぶ 本を積む 本を燃やす 本を燃やす 本を燃やす 本を燃やす
  7. 7. ConcurrencyとGoroutine ■ GoroutineでConcurrencyを実現 ● 複数のGoroutineで同時に複数のタスクをこなす ● 各Goroutineに役割を与えて分業する ■ 軽量なスレッドのようなもの ● LinuxやUnixのスレッドよりコストが低い ● 1つのスレッドの上で複数のGoroutineが動く ■ Goroutineの作り方 ● goキーワードをつけて関数を呼び出す go fnc() 複数のコアで動くとは限らない
  8. 8. 無名関数とGoroutine package main import "fmt" import "time" func main() { go func() { fmt.Println("別のゴールーチン") }() fmt.Println("mainゴールーチン") time.Sleep(50*time.Millisecond) } Sleepしないとすぐに終了する http://play.golang.org/p/jy1HWriRTS
  9. 9. Goroutine-main Goroutine間のデータのやり取り Goroutine-2 go f2() Goroutine-1 go f1()
  10. 10. Goroutine-main Goroutine間のデータのやり取り Goroutine-2 go f2() Goroutine-1 go f1() 変数v print(v) v = 100 共有の変数を使う?
  11. 11. 共有の変数を使う func main() { done := false go func() { time.Sleep(3 * time.Second) done = true }() for !done { time.Sleep(time.Millisecond) } fmt.Println("done!") } 共有の変数を使う http://play.golang.org/p/mGSOaq4mcr
  12. 12. Goroutine-main Goroutine間のデータのやり取り Goroutine-2 go f2() Goroutine-1 go f1() 変数v print(v) v = 100 処理順序が保証されない! 競合
  13. 13. 共有の変数を使う n := 1 go func() { for i := 2; i <= 5; i++ { fmt.Println(n, "*", i) n *= i time.Sleep(100) } }() http://play.golang.org/p/yqk82u0E4V for i := 1; i <= 10; i++ { fmt.Println(n, "+", i) n += 1 time.Sleep(100) } 競合
  14. 14. データ競合の解決方法 ■ 問題点 ● どのGoroutineが先にアクセスするか分からない ● 値の変更や参照が競合する ■ 解決方法 ● 1つの変数には1つのGoroutineからアクセスする ● Channelを使ってGoroutine間で通信をする ● またはロックをとる(syncパッケージ) "Do not communicate by sharing memory; instead, share memory by communicating"
  15. 15. Goroutine-main Channelとは? Goroutine-2 go f2() Goroutine-1 go f1() Channel 100 ch<-100<-ch Goroutine間でデータの通信 を行うパイプのようなもの
  16. 16. Channelの特徴 ■ 送受信できる型 ● Channelを定義する際に型を指定する ■ バッファ ● Channelにバッファを持たせることができる ● 初期化時に指定できる ● 指定しないと容量0となる ■ 送受信時の処理のブロック ● 送信時にChannelのバッファが一杯だとブロック ● 受信時にChannel内が空だとブロック
  17. 17. Goroutine-main 送信時のブロック Goroutine-2 go f2() Goroutine-1 go f1() Channel 100 ch<-100 受信してくれるまでブロック ブロック
  18. 18. Goroutine-main 受信時のブロック Goroutine-2 go f2() Goroutine-1 go f1() Channel 100 <-ch 送信してくれるまでブロック ブロック
  19. 19. Channelの基本 ■ 初期化 ■ 送信 ■ 受信 ch1 := make(chan int) ch2 := make(chan int, 10) ch1 <- 10 ch2 <- 10 + 20 n1 := <-ch1 n2 := <-ch2 + 100 容量を指定 受け取られるまでブロック 一杯であればブロック 送信されまでブロック 空であればブロック make(chan int, 0)と同じ
  20. 20. Channelの基本 func main() { done := make(chan bool) // 容量0 go func() { time.Sleep(time.Second * 3) done <- true }() <-done fmt.Println("done") } 送信されるまでブロック http://play.golang.org/p/k0sMCYe4PA
  21. 21. Goroutine-main 複数のChannelから同時に受信 Goroutine-2 go f2() Goroutine-1 go f1() ブロックされるので 同時に送受信出来ない? Channel-1 Channel-2 ブロック
  22. 22. Goroutine-main 複数のChannelから同時に受信 Goroutine-2 go f2() Goroutine-1 go f1() select-caseを使うと 同時に送受信できる Channel-1 Channel-2 select
  23. 23. select-case func main() { ch1 := make(chan int) ch2 := make(chan string) go func() { ch1<-100 }() go func() { ch2<-"hi" }() select { case v1 := <-ch1: fmt.Println(v1) case v2 := <-ch2: fmt.Println(v2) } } http://play.golang.org/p/moVwtEdQIv 先に受信した方を処理
  24. 24. nil Channel func main() { ch1 := make(chan int) var ch2 chan string go func() { ch1<-100 }() go func() { ch2<-"hi" }() select { case v1 := <-ch1: fmt.Println(v1) case v2 := <-ch2: fmt.Println(v2) } } http://play.golang.org/p/UcqW6WH0XT nilの場合は無視される ゼロ値はnil
  25. 25. ファーストクラスオブジェクト ■ ファーストクラスオブジェクト ● 変数に入れれる ● 引数に渡す ● 戻り値で返す ● ChannelのChannel ■ timeパッケージ // 5分間待つ <-time.After(5 * time.Minute) http://golang.org/pkg/time/#After chan chan int など 5分たったら現在時刻が 送られてくるChannelを返す
  26. 26. Channelを引数や戻り値にする func makeCh() chan int { return make(chan int) } func recvCh(recv chan int) int { return <-recv } func main() { ch := makeCh() go func() { ch <- 100 } fmt.Println(recvCh(ch)) } http://play.golang.org/p/vg2RhcdNWR
  27. 27. 双方向のChannel func makeCh() chan int { return make(chan int) } func recvCh(recv chan int) int { go func() { recv <- 200 }() return <-recv } func main() { ch := makeCh() go func() { ch <- 100 }() fmt.Println(recvCh(ch)) } http://play.golang.org/p/6gU92C6Q2v 間違った使い方ができる
  28. 28. 単方向のChannel func makeCh() chan int { return make(chan int) } func recvCh(recv <-chan int) int { return <-recv } func main() { ch := makeCh() go func(ch chan<- int) {ch <- 100}(ch) fmt.Println(recvCh(ch)) } http://play.golang.org/p/pY4u1PU3SU 受信専用のChannel 送信専用のChannel
  29. 29. Concurrencyを実現する ■ 複数Goroutineで分業する ● タスクの種類によってGoroutineを作る ● Concurrencyを実現 ■ Channelでやりとりする ● Goroutine間はChannelで値を共有する ● 複雑すぎる場合はロックを使うことも ■ for-selectパターン ● Goroutineごとに無限ループを作る ● メインのGoroutineはselectで結果を受信
  30. 30. Goroutine-main for-selectパターン Goroutine-2 go f2() Goroutine-1 go f1() 各Goroutineで 無限ループを作る Channel-1 Channel-2 select for{} for{}
  31. 31. つまりこういうこと Goroutine-1 for{} Goroutine-2 for{} Goroutine-3 for{} Goroutine-4 for{} Channel Channel Channel Channel
  32. 32. まとめ ■ GoroutineでConcurrencyを実現 ● go f()で簡単に作れる ■ Channelでやりとりする ● 送受信時のブロック ● ファーストクラスオブジェクト ● 単方向のChannel ■ for-selectパターン ● Goroutineごとに無限ループを作る ● メインのGoroutineはselectで結果を受信
  33. 33. 何か作って発表しよう ■ Go Conferenceに参加しよう http://eventdots.jp/event/573121
  34. 34. 何か作って記事を書こう ■ Go Advent Calendar ● http://qiita.com/advent-calendar/2015/go ● http://qiita.com/advent-calendar/2015/go2 ● http://qiita.com/advent-calendar/2015/go3 誰かgo4とgo5を!
  1. A particular slide catching your eye?

    Clipping is a handy way to collect important slides you want to go back to later.

×