これは僕が業に触れた話
この世界を繋ぐあらゆる理は、阿頼耶識の生み出した白昼夢なのかもしれない。最近、僕が僕であるために生きるということ自体が苦楽を含んだ報いなのだと思うようになった。それで生活が変わるわけでもないが……。
という妄想をしていたら夜になっていました。
Go Gou Golang
ということで、妄想だけ綴ってもアレですしGo言語の話をします。
ということで、Go言語の特徴の一つである「Concurrency」をやっていきます。聞きなれない単語ですが「並行性」とか訳される単語です。意味合いとしては処理の状態を複数保っている感じでしょうか。時間軸で示すと、同時に実行しているわけでなくただ実行のタスクを保持して、終了したら次をさばくみたいなイメージです。
1. Goroutines
ゴルーチンという謎用語が出てきますが、Go言語の生み出したコルーチン*1的なやつです。
実行するにはこれでいけるらしいです。
go 関数( )
func say(s string) { for i := 0; i < 5; i++ { time.Sleep(100 * time.Millisecond) fmt.Println(s) } } func main() { go say("赤あげて") go say("白あげないで") go say("赤あげないで") go say("白あげて") say(" ") }
処理を担保しているけども、別に交互に実行するわけでもない(※実行順は担保されない)のでランダム性がうまれてなんかゲームっぽい挙動になる。
2. Channels
ゴルーチン間の連携をつかさどるチャネルについて、チャネルオペレータの<-
を用いて値の送受信ができるようです。
・チャネルの受信
ch <- v // v をチャネル ch へ送信する v := <-ch // ch から受信した変数を v へ割り当てる
・チャネルの作成
ch := make(chan int)
3. Buffered Channels
チャネルを作るときに第二引数をいじるとバッファ上限をいじれるようです。
ch := make(chan int, バッファの長さ)
バッファが詰まるよう例文をいじってみるとこんな感じで怒られる。
fatal error: all goroutines are asleep - deadlock!
4. Range and Close
チャネルのクローズについての確認
v, ok := <-ch
チャネルのクローズ
close(ch)
5. Select
6. Default Selection
select
を使うことで複数の通信操作ができるようになる。どのcase
も準備できていない場合はデフォルトに行くそうです。
select { case i := <-c: // use i default: // receiving from c would block } }
サンプル
func main() { tick := time.Tick(100 * time.Millisecond) boom := time.After(500 * time.Millisecond) for { select { case <-tick: fmt.Println("tick.") case <-boom: fmt.Println("BOOM!") return default: fmt.Println(" .") time.Sleep(50 * time.Millisecond) } } }
7-8. Exercise: Equivalent Binary Trees
突然の実習問題!! 二分木が同じ値を保持するか問題
package main import "code.google.com/p/go-tour/tree" import "fmt" // Walk walks the tree t sending all values // from the tree to the channel ch. func Walk(t *tree.Tree, ch chan int){ var walk func(*tree.Tree) walk = func(t *tree.Tree) { if t != nil { walk(t.Left) ch <- t.Value walk(t.Right) } } walk(t) close(ch) } // Same determines whether the trees // t1 and t2 contain the same values. func Same(t1, t2 *tree.Tree) bool { c1,c2 := make(chan int), make(chan int) go Walk(t1, c1) go Walk(t2, c2) for { n1, ok1 := <-c1 n2, ok2 := <-c2 if n1 != n2 || ok1 != ok2 { return false } if !ok1 { break } } return true } func main() { fmt.Println(Same(tree.New(1), tree.New(1))) fmt.Println(Same(tree.New(1), tree.New(2))) }
多分こんな感じ。マジで自信ない。Treeパッケージが強すぎてどうにでもなる気がして、うまく動いている気が全然しない。
9.sync.Mutex
sync
パッケージを利用することで、排他ロックが効くそうです。
sync - The Go Programming Language
10. Exercise: Web Crawler
突然の実習問題!!ウェブクローラを並"列"化するお。
package main import ( "fmt" "sync" ) type Fetcher interface { // Fetch returns the body of URL and // a slice of URLs found on that page. Fetch(url string) (body string, urls []string, err error) } // Crawl uses fetcher to recursively crawl // pages starting with url, to a maximum of depth. func Crawl(url string, depth int, fetcher Fetcher) { // TODO: Fetch URLs in parallel. // TODO: Don't fetch the same URL twice. // This implementation doesn't do either: isFetched := make(map[string]bool) crawl(url, depth, fetcher, isFetched) return } func crawl(url string, depth int, fetcher Fetcher, isFetched map[string]bool) { if depth <= 0 { return } if _, ok := isFetched[url]; ok { return } body, urls, err := fetcher.Fetch(url) if err != nil { fmt.Println(err) return } fmt.Printf("found: %s %q\n", url, body) isFetched[url] = true // WaitGroup var wg sync.WaitGroup for _, u := range urls { wg.Add(1) go func(u string) { defer wg.Done() crawl(u, depth-1, fetcher, isFetched) }(u) } wg.Wait() return } func main() { Crawl("http://golang.org/", 4, fetcher) } // fakeFetcher is Fetcher that returns canned results. type fakeFetcher map[string]*fakeResult type fakeResult struct { body string urls []string } func (f fakeFetcher) Fetch(url string) (string, []string, error) { if res, ok := f[url]; ok { return res.body, res.urls, nil } return "", nil, fmt.Errorf("not found: %s", url) } // fetcher is a populated fakeFetcher. var fetcher = fakeFetcher{ "http://golang.org/": &fakeResult{ "The Go Programming Language", []string{ "http://golang.org/pkg/", "http://golang.org/cmd/", }, }, "http://golang.org/pkg/": &fakeResult{ "Packages", []string{ "http://golang.org/", "http://golang.org/cmd/", "http://golang.org/pkg/fmt/", "http://golang.org/pkg/os/", }, }, "http://golang.org/pkg/fmt/": &fakeResult{ "Package fmt", []string{ "http://golang.org/", "http://golang.org/pkg/", }, }, "http://golang.org/pkg/os/": &fakeResult{ "Package os", []string{ "http://golang.org/", "http://golang.org/pkg/", }, }, }
多分こんな感じ、全然わからん。WaitGroup
を使うことで良い感じになるらしいということがググってみてわかった。
おわった
かなり理解が怪しい部分があるけど終わらせた。とりあえず演習問題難しかった。分からんとかやりながら書き直すたびにコードがどんどん短くなっていっていったのはGoっぽい書き方ができるようになってきたからなのか……。まあ、いいや。これにてGoツアー終了です。
終