Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.
Goroutineと
Channelから
はじめるGo言語
ver. 5
2015/11/26(木)
@「最近、Go言語始めました」の会
The Go gopher was designed by Renee French.
The gophe...
アジェンダ
● 自己紹介
● Goとは?
● Goroutineの基本
● GoroutineとChannel
● 複数のChannelを扱う
● ファーストクラスオブジェクト
● 単方向のChannel
● for-selectパターン
自己紹介
KLab株式会社
KLabGames事業本部 エンジニア
上田拓也
twitter: @tenntenn
■ 好きな言語
Go, JavaScript, Lua
■ 業務
モバイルオンラインゲームの開発(クライアントサイド)
Goとは?
Googleが開発しているプログラミング言語
■ 特徴
● 並行プログラミング
● 豊富なライブラリ群
● 強力でシンプルな言語設計と文法
● クロスコンパイル/シングルバイナリ
● go tool
Concurrency is not Parallelism
■ ConcurrencyとParallelismは違う
● Concurrency => 並行
● Parallelism => 並列
■ Concurrency
● 同時にいくつ...
Concurrency is not Parallelism
■ Concurrency
■ Parallelism
本を運ぶ
本を燃やす
台車を運ぶ
本を積む
本を燃やす 本を燃やす 本を燃やす 本を燃やす
ConcurrencyとGoroutine
■ GoroutineでConcurrencyを実現
● 複数のGoroutineで同時に複数のタスクをこなす
● 各Goroutineに役割を与えて分業する
■ 軽量なスレッドのようなもの
● Li...
無名関数とGoroutine
package main
import "fmt"
import "time"
func main() {
go func() {
fmt.Println("別のゴールーチン")
}()
fmt.Println("...
Goroutine-main
Goroutine間のデータのやり取り
Goroutine-2
go f2()
Goroutine-1
go f1()
Goroutine-main
Goroutine間のデータのやり取り
Goroutine-2
go f2()
Goroutine-1
go f1()
変数v
print(v) v = 100
共有の変数を使う?
共有の変数を使う
func main() {
done := false
go func() {
time.Sleep(3 * time.Second)
done = true
}()
for !done {
time.Sleep(time.M...
Goroutine-main
Goroutine間のデータのやり取り
Goroutine-2
go f2()
Goroutine-1
go f1()
変数v
print(v) v = 100
処理順序が保証されない!
競合
共有の変数を使う
n := 1
go func() {
for i := 2; i <= 5; i++ {
fmt.Println(n, "*", i)
n *= i
time.Sleep(100)
}
}()
http://play.gola...
データ競合の解決方法
■ 問題点
● どのGoroutineが先にアクセスするか分からない
● 値の変更や参照が競合する
■ 解決方法
● 1つの変数には1つのGoroutineからアクセスする
● Channelを使ってGoroutine間で...
Goroutine-main
Channelとは?
Goroutine-2
go f2()
Goroutine-1
go f1()
Channel
100
ch<-100<-ch
Goroutine間でデータの通信
を行うパイプのようなもの
Channelの特徴
■ 送受信できる型
● Channelを定義する際に型を指定する
■ バッファ
● Channelにバッファを持たせることができる
● 初期化時に指定できる
● 指定しないと容量0となる
■ 送受信時の処理のブロック
● ...
Goroutine-main
送信時のブロック
Goroutine-2
go f2()
Goroutine-1
go f1()
Channel
100
ch<-100
受信してくれるまでブロック
ブロック
Goroutine-main
受信時のブロック
Goroutine-2
go f2()
Goroutine-1
go f1()
Channel
100
<-ch
送信してくれるまでブロック
ブロック
Channelの基本
■ 初期化
■ 送信
■ 受信
ch1 := make(chan int)
ch2 := make(chan int, 10)
ch1 <- 10
ch2 <- 10 + 20
n1 := <-ch1
n2 := <-ch...
Channelの基本
func main() {
done := make(chan bool) // 容量0
go func() {
time.Sleep(time.Second * 3)
done <- true
}()
<-done
fm...
Goroutine-main
複数のChannelから同時に受信
Goroutine-2
go f2()
Goroutine-1
go f1()
ブロックされるので
同時に送受信出来ない?
Channel-1 Channel-2
ブロック
Goroutine-main
複数のChannelから同時に受信
Goroutine-2
go f2()
Goroutine-1
go f1()
select-caseを使うと
同時に送受信できる
Channel-1 Channel-2
sel...
select-case
func main() {
ch1 := make(chan int)
ch2 := make(chan string)
go func() { ch1<-100 }()
go func() { ch2<-"hi" }(...
nil Channel
func main() {
ch1 := make(chan int)
var ch2 chan string
go func() { ch1<-100 }()
go func() { ch2<-"hi" }()
sel...
ファーストクラスオブジェクト
■ ファーストクラスオブジェクト
● 変数に入れれる
● 引数に渡す
● 戻り値で返す
● ChannelのChannel
■ timeパッケージ
// 5分間待つ
<-time.After(5 * time.Mi...
Channelを引数や戻り値にする
func makeCh() chan int {
return make(chan int)
}
func recvCh(recv chan int) int {
return <-recv
}
func m...
双方向のChannel
func makeCh() chan int {
return make(chan int)
}
func recvCh(recv chan int) int {
go func() { recv <- 200 }()
...
単方向のChannel
func makeCh() chan int {
return make(chan int)
}
func recvCh(recv <-chan int) int {
return <-recv
}
func main(...
Concurrencyを実現する
■ 複数Goroutineで分業する
● タスクの種類によってGoroutineを作る
● Concurrencyを実現
■ Channelでやりとりする
● Goroutine間はChannelで値を共有する...
Goroutine-main
for-selectパターン
Goroutine-2
go f2()
Goroutine-1
go f1()
各Goroutineで
無限ループを作る
Channel-1 Channel-2
select
for{...
つまりこういうこと
Goroutine-1
for{}
Goroutine-2
for{}
Goroutine-3
for{}
Goroutine-4
for{}
Channel
Channel
Channel
Channel
まとめ
■ GoroutineでConcurrencyを実現
● go f()で簡単に作れる
■ Channelでやりとりする
● 送受信時のブロック
● ファーストクラスオブジェクト
● 単方向のChannel
■ for-selectパター...
何か作って発表しよう
■ Go Conferenceに参加しよう
http://eventdots.jp/event/573121
何か作って記事を書こう
■ Go Advent Calendar
● http://qiita.com/advent-calendar/2015/go
● http://qiita.com/advent-calendar/2015/go2
● ...
Goroutineと channelから はじめるgo言語
Upcoming SlideShare
Loading in …5
×

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

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

  • Login to see the comments

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

×