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

41
GoroutineChannelから はじめるGo言語 ver. 3 2014/1/18() @初心者向けgolang勉強会

Upload: takuya-ueda

Post on 24-May-2015

2.842 views

Category:

Documents


6 download

TRANSCRIPT

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

GoroutineとChannelからはじめるGo言語ver. 3

2014/1/18(土)@初心者向けgolang勉強会

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

自己紹介

上田拓也KLab株式会社

仕事:

 ・サーバサイド(PHP) ・フロントエンド(JS)学生のころ:

 ・セルオートマトン

 ・複雑系

twitter : @tenntenn

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

アジェンダ

● Go言語とは

● GorotuineとChannel

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

Go言語とは?

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

Go言語ってなに?

● え?Go言語知らない?● ビッグウェーブに乗り遅れてますよ!

Googleトレンド

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

Go言語とは?

● Googleが開発したコンパイラ言語

○ その他のGoogleが開発した言語

■ Dart : JSの代替

■ noop : JavaVMで動く言語(忘却のかなた)

● 設計者:

Robert Grisemer, Rob Pike, Ken Thompson

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

Go言語の特徴

● シンプルな文法/設計○ 曖昧さを排除した設計○ 強い静的型付け○ 型推論ができるので、型を省略できる○ ポインタはあるがポインタ演算はなし○ 複数の戻り値を返す関数○ ダックタイピング○ ゼロ値初期化

● ゴールーチンとチャネル● 豊富なライブラリ群

○ goツールは最強

○ Web系パッケージの豊富さ

○ Google App Engine for go

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

主なGo言語の勉強会@東京

● GoCon spring, autumn○ Go言語の勉強会では一番規模の大きい○ Go言語の中の人が来る

● 質実Go研○ 標準ライブラリを中心にソースを読む会○ 少人数で濃い話をする

● 電車でGo!○ 電車に乗りながらGo言語をする

● Go羅温泉○ 強羅温泉でGo言語をする

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

私とGo言語

● 研究で使うために始める

○ セルオートマトンシミュレータを作るため

● 主にGDG名古屋で活動していた

○ スタートGo #0, #1

● CodeIQにて問題を出題

● 社内でGo会を開催している

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

初心者向けの情報

● Tour of Go○ Web上でGo言語の一通りいじれる

● Go言語の初心者が見ると幸せになれる場所○ http://qiita.

com/tenntenn/items/0e33a4959250d1a55045

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

Gorotuineと

Channel

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

Concurrency is not Parallelism● ConcurrencyとParallelismは違う by Rob Pike

○ Concurrency=並行?

○ Parallelism=並列?

● Concurrency

○ 同時にいくつかの事を扱う事

● Parallelism

○ 同時にいくつかの計算を行なう事

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

Concurrency is... by Rob PikeRob Pike氏のプレゼンのまとめでは、

○ Concurrency is powerful.

○ Concurrency is not parallelism.

○ Concurrency enables parallelism.

○ Concurrency makes parallelism (and scaling

and everything else) easy.

とある。

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

Gorotuineとは?

● Go言語ではゴールーチンを用いてConcurrencyを実

現している

● スレッドに似ている...○ しかし、もっとCheap(=コストが低い)

○ LinuxやUnixのスレッドとは違う

■ スレッドの上にいくつも乗っている

● 簡単に作成できる

○ 関数呼び出しの前にgoキーワードを付ける

■ go f()

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

go + クロージャ

http://play.golang.org/p/4DT57uR4gD

package mainimport "fmt"func main() {

go func() {fmt.Println("別のゴールーチン")

}()fmt.Println("mainゴールーチン")

}

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

並列度

● 並列度:GOMAXPROCS○ 同時に最大で実行可能なCPU数

● デフォルトでは並列度は1になっている

○ runtime.NumCPU()で利用可能なCPU数が取得

できる

○ runtime.GOMAXPROCS()で並列度を設定する

【例】

runtime.GOMAXPROCS(runtime.NumCPU())● 指定した並列度でゴールーチンを動かす

○ あまり増やしても意味がない

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

Goroutine間のデータのやりとりは?

Goroutine-1 Goroutine-2

go f1() go f2()

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

共有の変数を使う?

Goroutine-1 Goroutine-2

go f1() go f2()

変数v v = 100fmt.Println(v)

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

Goroutine間のデータのやりとり

● 共有の変数を使う?http://play.golang.org/p/mGSOaq4mcr

func main() {done := falsego func() {

time.Sleep(time.Second * 3)done = true

}()for !done {

time.Sleep(time.Millisecond)}fmt.Println("done!")

}

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

競合が起きますよね!

Goroutine-1 Goroutine-2

go f1() go f2()

変数v v = 100v = 200

競合

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

Goroutine間のデータの競合// これはダメ!!

package mainimport "fmt"import "time"func main() {

n := 1go func() {

for i := 2; i <= 5; i++ {fmt.Println(n, "*", i)n *= i

}}()

// 続く

// 続き

for i := 1; i <= 10; i++ {fmt.Println(n, "+", i)n += 1time.Sleep(500)

}}

http://play.golang.org/p/NJuV6P7TIf

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

何が問題なのか?どう解決するの?

【問題】

● 同時に複数のGoroutineからアクセス

● 競合が起きる

【解決方法】

● 1つのGoroutineからのみアクセスする

● Channelを使う!

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

Channelを使う

Goroutine-1 Goroutine-2

go f1() go f2()

ch <- 100Channel

<-ch

100

● Goroutine間でデータをやりとりするパイプ?のような

もの

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

Channelの特徴

● 送受信するデータの型が決まっている

○ 型を指定してChannelを作る

● 一度に保持できる容量がある

○ 初期化の際に容量を指定、デフォルトは0

● 送受信の際に相手の応答を待つ

○ 容量が0になると、受信元が受け取るまでブロックされる

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

送信のブロック

Goroutine-1 Goroutine-2

go f1() go f2()

ch <- 100Channel

100

ブロック

● 相手が受信(<-ch)してくれるまで、次に進めない

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

受信のブロック

Goroutine-1 Goroutine-2

go f1() go f2()

Channel

100ブロック

● 相手が送信(ch<-100)してくれるまで、次に進めない

<-ch

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

Channelの宣言方法と使い方

● 宣言○ ch := make(chan 型) // 容量0○ ch := make(chan 型, 容量)

● 送信○ ch <- 100○ ch <- "hoge"

■ 容量いっぱいであれば取り出されるの待機する

■ 容量0の場合は常に待つ

● 受信○ n := <- ch

■ 送られてくるまで待機する

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

Channelの宣言方法と使い方

http://play.golang.org/p/k0sMCYe4PAfunc main() {

done := make(chan bool) // 容量0go func() {

time.Sleep(time.Second * 3)done <- true

}()<-done // 待つ

fmt.Println("done")}

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

こういう場合はどうするの?

Goroutine-1

Goroutine-2

go f1() go f2()

Channel-1

● ブロックするなら複数のChannelからデータを受け取

れない!?

Goroutine-3

<-ch1

Channel-2

go f3()

<-ch2

ch1 <- 100

ch2 <- "hoge"

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

selectを使う

Goroutine-1

Goroutine-2

go f1() go f2()

Channel-1

● selectを使えば、同時に複数のchannelから受信でき

Goroutine-3Channel-2

go f3()

<-ch2

ch1 <- 100

ch2 <- "hoge"sele

ct <-ch1

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

selectを使う

● 先に受信可能になったcaseを実行する

// Goroutine-1にて

select {case v1 := <-ch1:

// Goroutine-2から ch1 <- 100case v2 := <-ch2:

// Goroutine-3から ch2 <- "hoge"}※Channelがnilだとそのcaseは無視:nil channel http://play.golang.org/p/7fNEkf9B8H

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

ReadOnlyとWriteOnly● 通常のチャネルは双方向

○ 引数や戻り値で渡す場合は困る

func hoge(in chan int) {n := <-in // 入力として使うのが正解!

in <- 100 // 間違った使い方ができる!

}

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

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)

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

ファーストクラスオブジェクト

● Channelはファーストクラスオブジェクト○ 変数に入れれる

○ 引数に渡せる

○ 戻り値に取れる

○ ChannelのChannel● 戻り値として、チャネルを返す関数は多用される

○ timeパッケージ

○ 5分間待つ

<-time.After(5 * time.Minute)http://golang.org/pkg/time/#After

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

range● for文のrangeで送られてくるデータを次々に取

り出せる

http://play.golang.org/p/OSSSzRY8GT// 1秒ごとに現在時間を出す

for now := range time.Tick(1 * time.Second) {fmt.Println(now)

}

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

どう使って行くのか?

● 沢山の独立したゴールーチンがチャネルを使っ

てやり取りをする!○ Concurrencyになる

● ゴールーチンのコストは安いので、沢山作って

もそんなに問題ない○ ※コストが0ではない

● for - selectパターン

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

for - selectパターン

Goroutine-1Channel-1

Channel-2

sele

ct

for{}

Goroutine-2

for{}

Goroutine-3

for{}

● 各Goroutineが無限ループになっており、イベントリス

ナー的にChannelを使うパターン

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

Gopher君で表すとこんな感じ!

ひたすら本を入れる

ひたすら本を運ぶ

ひたすら台車を運ぶ

ひたすら本を燃やす

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

構成要素の局所的な振る舞いが相互作用する事によって複雑な現象を作り出す

複雑系みたいで楽しい!

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

まとめ

● GoroutineはConcurrencyを実現する機構

○ go f() で簡単に作れる

● ChannelはGoroutine間のデータのやり取りに

使う

○ 送受信のブロック

○ select〜case文

○ ファーストクラスオブジェクト

○ select - forパターン