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言語
2013/9/28(土)
@初心者向けgolang勉強会
自己紹介
上田拓也
KLab株式会社
仕事:
 ・サーバサイド(PHP)
 ・フロントエンド(JS)
学生のころ:
 ・セルオートマトン
 ・複雑系
twitter : @tenntenn
アジェンダ
● Go言語とは
● GorotuineとChannel
Go言語とは?
Go言語ってなに?
● え?Go言語知らない?
● ビッグウェーブに乗り遅れてますよ!
Googleトレンド
Go言語とは?
● Googleが開発したコンパイラ言語
○ その他のGoogleが開発した言語
■ Dart : JSの代替
■ noop : JavaVMで動く言語(忘却のかなた)
● 設計者:
Robert Grisemer, Rob P...
Go言語の特徴
● シンプルな文法/設計
○ 曖昧さを排除した設計
○ 強い静的型付け
○ 型推論ができるので、型を省略できる
○ ポインタはあるがポインタ演算はなし
○ 複数の戻り値を返す関数
○ ダックタイピング
○ ゼロ値初期化
● ゴー...
主なGo言語の勉強会@東京
● GoCon spring, autumn
○ Go言語の勉強会では一番規模の大きい
○ Go言語の中の人が来る
● 質実Go研
○ 標準ライブラリを中心にソースを読む会
○ 少人数で濃い話をする
● 電車でGo!...
私とGo言語
● 研究で使うために始める
○ セルオートマトンシミュレータを作るため
● 主にGDG名古屋で活動していた
○ スタートGo #0, #1
● CodeIQにて問題を出題
● 社内でGo会を開催している
初心者向けの情報
● Tour of Go
○ Web上でGo言語の一通りいじれる
● Go言語の初心者が見ると幸せになれる場所
○ http://qiita.
com/tenntenn/items/0e33a4959250d1a55
045
Gorotuine
と
Channel
Concurrency is not Parallelism
● ConcurrencyとParallelismは違う by Rob Pike
○ Concurrency=並行?
○ Parallelism=並列?
● Concurrency
...
Concurrency is... by Rob Pike
Rob Pike氏のプレゼンのまとめでは、
○ Concurrency is powerful.
○ Concurrency is not parallelism.
○ Concurr...
Gorotuineとは?
● Go言語ではゴールーチンを用いてConcurrencyを実
現している
● スレッドに似ている...
○ しかし、もっとCheap(=コストが低い)
○ LinuxやUnixのスレッドとは違う
■ スレッドの上にい...
go + クロージャ
package main
import "fmt"
func main() {
go func() {
fmt.Println("別のゴールーチン")
}()
fmt.Println("mainゴールーチン")
}
並列度
● 並列度:GOMAXPROCS
○ 同時に最大で実行可能なCPU数
● デフォルトでは並列度は1になっている
○ runtime.NumCPU()で利用可能なCPU数が取得
できる
○ runtime.GOMAXPROCS()で並列度...
Goroutine間のデータのやりとりは?
Goroutine-1 Goroutine-2
go f1() go f2()
共有の変数を使う?
Goroutine-1 Goroutine-2
go f1() go f2()
変数v v = 100fmt.Println(v)
Goroutine間のデータのやりとり
● 共有の変数を使う?
func main() {
done := false
go func() {
time.Sleep(time.Second * 3)
done = true
}()
for !d...
競合が起きますよね!
Goroutine-1 Goroutine-2
go f1() go f2()
変数v v = 100v = 200
競合
Goroutine間のデータの競合
// これはダメ!!
package main
import "fmt"
import "time"
func main() {
n := 1
go func() {
for i := 2; i <= 5; ...
何が問題なのか?どう解決するの?
【問題】
● 同時に複数のGoroutineからアクセス
● 競合が起きる
【解決方法】
● 1つのGoroutineからのみアクセスする
● Channelを使う!
Channelを使う
Goroutine-1 Goroutine-2
go f1() go f2()
ch <- 100
Channel
<-ch
100
● Goroutine間でデータをやりとりするパイプ?のような
もの
Channelの特徴
● 送受信するデータの型が決まっている
○ 型を指定してChannelを作る
● 一度に保持できる容量がある
○ 初期化の際に容量を指定、デフォルトは0
● 送受信の際に相手の応答を待つ
○ 容量が0になると、受信元が受け...
送信のブロック
Goroutine-1 Goroutine-2
go f1() go f2()
ch <- 100
Channel
100
ブロック
● 相手が受信(<-ch)してくれるまで、次に進めない
受信のブロック
Goroutine-1 Goroutine-2
go f1() go f2()
Channel
100
ブロック
● 相手が送信(ch<-100)してくれるまで、次に進めない
<-ch
Channelの宣言方法と使い方
● 宣言
○ ch := make(chan 型) // 容量0
○ ch := make(chan 型, 容量)
● 送信
○ ch <- 100
○ ch <- "hoge"
■ 容量いっぱいであれば取り出...
Channelの宣言方法と使い方
func main() {
done := make(chan bool) // 容量0
go func() {
time.Sleep(time.Second * 3)
done <- true
}()
<-d...
こういう場合はどうするの?
Goroutine-1
Goroutine-2
go f1() go f2()
Channel-1
● ブロックするなら複数のChannelからデータを受け取
れない!?
Goroutine-3
<-ch1
Chan...
selectを使う
Goroutine-1
Goroutine-2
go f1() go f2()
Channel-1
● selectを使えば、同時に複数のchannelから受信でき
る
Goroutine-3Channel-2
go f3(...
selectを使う
● 先に受信可能になったcaseを実行する
// Goroutine-1にて
select {
case v1 := <-ch1:
// Goroutine-2から ch1 <- 100
case v2 := <-ch2:
...
ReadOnlyとWriteOnly
● 通常のチャネルは双方向
○ 引数や戻り値で渡す場合は困る
func hoge(in chan int) {
n := <-in // 入力として使うのが正解!
in <- 100 // 間違った使い方が...
ReadOnlyとWriteOnly
● ReadOnly
○ in := make(<-chan int)
● WriteOnly
○ out := make(chan<- int)
● キャスト
○ 双方向チャネルはキャストでReadOnl...
ファーストクラスオブジェクト
● Channelはファーストクラスオブジェクト
○ 変数に入れれる
○ 引数に渡せる
○ 戻り値に取れる
○ ChannelのChannel
● 戻り値として、チャネルを返す関数は多用される
○ timeパッケー...
range
● for文のrangeで送られてくるデータを次々に取
り出せる
// 1分ごとに現在時間を出す
for now := range time.Tick(1 * time.Minute) {
fmt.Println(now)
}
どう使って行くのか?
● 沢山の独立したゴールーチンがチャネルを使っ
てやり取りをする!
○ Concurrencyになる
● ゴールーチンのコストは安いので、沢山作って
もそんなに問題ない
○ ※コストが0ではない
● for - selec...
for - selectパターン
Goroutine-1
Channel-1
Channel-2
select
for{}
Goroutine-2
for{}
Goroutine-3
for{}
● 各Goroutineが無限ループになっており...
Gopher君で表すとこんな感じ!
ひたすら本を入れる
ひたすら本を運ぶ
ひたすら台車を運ぶ
ひたすら本を燃やす
構成要素の局所的な振る舞いが
相互作用する事によって
複雑な現象を作り出す
複雑系みたいで楽しい!
まとめ
● GoroutineはConcurrencyを実現する機構
○ go f() で簡単に作れる
● ChannelはGoroutine間のデータのやり取りに
使う
○ 送受信のブロック
○ select〜case文
○ ファーストクラス...
Upcoming SlideShare
Loading in …5
×

Goroutineとchannelから始めるgo言語@初心者向けgolang勉強会

14,535 views

Published on

初心者向けgolang勉強会で発表したスライドです。
http://atnd.org/events/42889

Published in: Technology

Goroutineとchannelから始めるgo言語@初心者向けgolang勉強会

  1. 1. Goroutineと Channelから はじめるGo言語 2013/9/28(土) @初心者向けgolang勉強会
  2. 2. 自己紹介 上田拓也 KLab株式会社 仕事:  ・サーバサイド(PHP)  ・フロントエンド(JS) 学生のころ:  ・セルオートマトン  ・複雑系 twitter : @tenntenn
  3. 3. アジェンダ ● Go言語とは ● GorotuineとChannel
  4. 4. Go言語とは?
  5. 5. Go言語ってなに? ● え?Go言語知らない? ● ビッグウェーブに乗り遅れてますよ! Googleトレンド
  6. 6. Go言語とは? ● Googleが開発したコンパイラ言語 ○ その他のGoogleが開発した言語 ■ Dart : JSの代替 ■ noop : JavaVMで動く言語(忘却のかなた) ● 設計者: Robert Grisemer, Rob Pike, Ken Thompson
  7. 7. Go言語の特徴 ● シンプルな文法/設計 ○ 曖昧さを排除した設計 ○ 強い静的型付け ○ 型推論ができるので、型を省略できる ○ ポインタはあるがポインタ演算はなし ○ 複数の戻り値を返す関数 ○ ダックタイピング ○ ゼロ値初期化 ● ゴールーチンとチャネル ● 豊富なライブラリ群 ○ goツールは最強 ○ Web系パッケージの豊富さ ○ Google App Engine for go
  8. 8. 主なGo言語の勉強会@東京 ● GoCon spring, autumn ○ Go言語の勉強会では一番規模の大きい ○ Go言語の中の人が来る ● 質実Go研 ○ 標準ライブラリを中心にソースを読む会 ○ 少人数で濃い話をする ● 電車でGo! ○ 電車に乗りながらGo言語をする ● Go羅温泉 ○ 強羅温泉でGo言語をする
  9. 9. 私とGo言語 ● 研究で使うために始める ○ セルオートマトンシミュレータを作るため ● 主にGDG名古屋で活動していた ○ スタートGo #0, #1 ● CodeIQにて問題を出題 ● 社内でGo会を開催している
  10. 10. 初心者向けの情報 ● Tour of Go ○ Web上でGo言語の一通りいじれる ● Go言語の初心者が見ると幸せになれる場所 ○ http://qiita. com/tenntenn/items/0e33a4959250d1a55 045
  11. 11. Gorotuine と Channel
  12. 12. Concurrency is not Parallelism ● ConcurrencyとParallelismは違う by Rob Pike ○ Concurrency=並行? ○ Parallelism=並列? ● Concurrency ○ 同時にいくつかの事を扱う事 ● Parallelism ○ 同時にいくつかの計算を行なう事
  13. 13. Concurrency is... by Rob Pike Rob Pike氏のプレゼンのまとめでは、 ○ Concurrency is powerful. ○ Concurrency is not parallelism. ○ Concurrency enables parallelism. ○ Concurrency makes parallelism (and scaling and everything else) easy. とある。
  14. 14. Gorotuineとは? ● Go言語ではゴールーチンを用いてConcurrencyを実 現している ● スレッドに似ている... ○ しかし、もっとCheap(=コストが低い) ○ LinuxやUnixのスレッドとは違う ■ スレッドの上にいくつも乗っている ● 簡単に作成できる ○ 関数呼び出しの前にgoキーワードを付ける ■ go f()
  15. 15. go + クロージャ package main import "fmt" func main() { go func() { fmt.Println("別のゴールーチン") }() fmt.Println("mainゴールーチン") }
  16. 16. 並列度 ● 並列度:GOMAXPROCS ○ 同時に最大で実行可能なCPU数 ● デフォルトでは並列度は1になっている ○ runtime.NumCPU()で利用可能なCPU数が取得 できる ○ runtime.GOMAXPROCS()で並列度を設定する 【例】 runtime.GOMAXPROCS(runtime.NumCPU()) ● 指定した並列度でゴールーチンを動かす ○ あまり増やしても意味がない
  17. 17. Goroutine間のデータのやりとりは? Goroutine-1 Goroutine-2 go f1() go f2()
  18. 18. 共有の変数を使う? Goroutine-1 Goroutine-2 go f1() go f2() 変数v v = 100fmt.Println(v)
  19. 19. Goroutine間のデータのやりとり ● 共有の変数を使う? func main() { done := false go func() { time.Sleep(time.Second * 3) done = true }() for !done { time.Sleep(time.Millisecond) } }
  20. 20. 競合が起きますよね! Goroutine-1 Goroutine-2 go f1() go f2() 変数v v = 100v = 200 競合
  21. 21. Goroutine間のデータの競合 // これはダメ!! package main import "fmt" import "time" func main() { n := 1 go func() { for i := 2; i <= 5; i++ { fmt.Println(n, "*", i) n *= i } }() // 続く // 続き for i := 1; i <= 10; i++ { fmt.Println(n, "+", i) n += 1 time.Sleep(500) } } だめ!!
  22. 22. 何が問題なのか?どう解決するの? 【問題】 ● 同時に複数のGoroutineからアクセス ● 競合が起きる 【解決方法】 ● 1つのGoroutineからのみアクセスする ● Channelを使う!
  23. 23. Channelを使う Goroutine-1 Goroutine-2 go f1() go f2() ch <- 100 Channel <-ch 100 ● Goroutine間でデータをやりとりするパイプ?のような もの
  24. 24. Channelの特徴 ● 送受信するデータの型が決まっている ○ 型を指定してChannelを作る ● 一度に保持できる容量がある ○ 初期化の際に容量を指定、デフォルトは0 ● 送受信の際に相手の応答を待つ ○ 容量が0になると、受信元が受け取るまでブロックされる
  25. 25. 送信のブロック Goroutine-1 Goroutine-2 go f1() go f2() ch <- 100 Channel 100 ブロック ● 相手が受信(<-ch)してくれるまで、次に進めない
  26. 26. 受信のブロック Goroutine-1 Goroutine-2 go f1() go f2() Channel 100 ブロック ● 相手が送信(ch<-100)してくれるまで、次に進めない <-ch
  27. 27. Channelの宣言方法と使い方 ● 宣言 ○ ch := make(chan 型) // 容量0 ○ ch := make(chan 型, 容量) ● 送信 ○ ch <- 100 ○ ch <- "hoge" ■ 容量いっぱいであれば取り出されるの待機する ■ 容量0の場合は常に待つ ● 受信 ○ n := <- ch ■ 送られてくるまで待機する
  28. 28. Channelの宣言方法と使い方 func main() { done := make(chan bool) // 容量0 go func() { time.Sleep(time.Second * 3) done <- true }() <-done // 待つ fmt.Println("done") }
  29. 29. こういう場合はどうするの? Goroutine-1 Goroutine-2 go f1() go f2() Channel-1 ● ブロックするなら複数のChannelからデータを受け取 れない!? Goroutine-3 <-ch1 Channel-2 go f3() <-ch2 ch1 <- 100 ch2 <- "hoge"
  30. 30. selectを使う Goroutine-1 Goroutine-2 go f1() go f2() Channel-1 ● selectを使えば、同時に複数のchannelから受信でき る Goroutine-3Channel-2 go f3() <-ch2 ch1 <- 100 ch2 <- "hoge" select <-ch1
  31. 31. selectを使う ● 先に受信可能になったcaseを実行する // Goroutine-1にて select { case v1 := <-ch1: // Goroutine-2から ch1 <- 100 case v2 := <-ch2: // Goroutine-3から ch2 <- "hoge" } ※Channelがnilだとそのcaseは無視:nil channel
  32. 32. ReadOnlyとWriteOnly ● 通常のチャネルは双方向 ○ 引数や戻り値で渡す場合は困る func hoge(in chan int) { n := <-in // 入力として使うのが正解! in <- 100 // 間違った使い方ができる! }
  33. 33. ReadOnlyとWriteOnly ● ReadOnly ○ in := make(<-chan int) ● WriteOnly ○ out := make(chan<- int) ● キャスト ○ 双方向チャネルはキャストでReadOnlyまたは WriteOnlyに変化できる ○ ch := make(chan int) ○ in := (<-chan int)(ch) ○ out := (chan<- int)(ch)
  34. 34. ファーストクラスオブジェクト ● Channelはファーストクラスオブジェクト ○ 変数に入れれる ○ 引数に渡せる ○ 戻り値に取れる ○ ChannelのChannel ● 戻り値として、チャネルを返す関数は多用される ○ timeパッケージ ○ 5分間待つ <-time.After(5 * time.Minute)
  35. 35. range ● for文のrangeで送られてくるデータを次々に取 り出せる // 1分ごとに現在時間を出す for now := range time.Tick(1 * time.Minute) { fmt.Println(now) }
  36. 36. どう使って行くのか? ● 沢山の独立したゴールーチンがチャネルを使っ てやり取りをする! ○ Concurrencyになる ● ゴールーチンのコストは安いので、沢山作って もそんなに問題ない ○ ※コストが0ではない ● for - selectパターン
  37. 37. for - selectパターン Goroutine-1 Channel-1 Channel-2 select for{} Goroutine-2 for{} Goroutine-3 for{} ● 各Goroutineが無限ループになっており、イベントリス ナー的にChannelを使うパターン
  38. 38. Gopher君で表すとこんな感じ! ひたすら本を入れる ひたすら本を運ぶ ひたすら台車を運ぶ ひたすら本を燃やす
  39. 39. 構成要素の局所的な振る舞いが 相互作用する事によって 複雑な現象を作り出す 複雑系みたいで楽しい!
  40. 40. まとめ ● GoroutineはConcurrencyを実現する機構 ○ go f() で簡単に作れる ● ChannelはGoroutine間のデータのやり取りに 使う ○ 送受信のブロック ○ select〜case文 ○ ファーストクラスオブジェクト ○ select - forパターン

×