【Go初学】Channelsは桃太郎
▼概要
Goの学習メモ。チャネルについて。
▼Channelsとは
goroutineで非同期処理の値の受け渡しに使われるもよう。
▼Goroutineとは
並行して処理を行う機構。
▼チャネルの概念の理解
Goの学習を進めていて最初に戸惑ったのがチャネルの存在。
恐らくC言語のポインタ仕様並に、初学者が最初に躓くポイントなんだろうと思う。
Microsoft学習カリキュラムの「MicroSoft Learn」でGoのカリキュラムがあるが、そちらでも「これまでに学んだことを忘れる必要があるかも」と言っているほど。
別の言語で触れたことがあるReactive系ライブラリの「Observableオブジェクトを使ったイベントストリームのようなもの」か?と捉えると、何をする目的のものなのかイメージが掴みやすかった。
イベントストリームの概念は、自分は桃太郎の桃が流れてくるのを待つシーンがそれにあたるかなと理解している。
- お婆さんが桃を待つだけの状態
川:イベントストリーム = channel
お婆さん:イベント購読者 = main goroutine
神:イベント発行者(桃を流す側) = 別goroutine
登場人物がお婆さんだけの状態だとどうなるか。お婆さんは桃(イベント)が流れてくることを期待している。
package main
func main() {
// 桃を流したら連絡してもらう手段を作成(イベントが発行されるストリーム)
momoChannel := make(chan bool)
// 桃が流れるのを待つ
<-momoChannel
}
連絡してもらう手段として糸電話(チャネル)を作成した。しかし誰にも糸電話を渡していないため、お婆さんは永遠に桃が流れるのを待ち続け、不謹慎なdeadlockとなる。
$ go run main.go
$ fatal error: all goroutines are asleep - deadlock!
- 神(イベント発行者)と約束
package main
import (
"fmt"
"time"
)
func main() {
// 桃を流したら連絡してもらう(イベントが発行されるストリーム)
momoChannel := make(chan bool)
// 神の御業
go func(channel chan bool) {
fmt.Println("桃を流す準備を開始")
// ちょっと時間が掛かった想定
time.Sleep(3 * time.Second)
// 流したことを連絡
fmt.Println("桃を流しました")
channel <- true
}(momoChannel)
// 桃が流れるのを待つ
<-momoChannel
fmt.Println("桃を手に入れました")
}
$ go run main.go
$ 桃を流す準備を開始
$ 桃を流しました
$ 桃を手に入れました
神(匿名関数のgoroutine)に連絡手段の糸電話(チャネル)を渡し、桃を流したら連絡する約束をした。神が桃を流したことを連絡したため、永遠に待ち続けることなくお婆さんは桃を手に入れることができた。
問題があるケースとして、糸電話なのでお婆さんが洗濯に行ったりして糸電話から離れる(チャネルを受信しない)と、神がお婆さんと連絡が取れなくなりお婆さん戻り待ちとなり、神の仕事がストップする。
またお婆さんが糸電話を渡しておいてすぐ「やっぱ桃いいわ」と糸電話を捨てる(close())と、神が連絡を取ろうとした時に文字通りパニック(panic())してエラーとなる。
あとがき
永遠に待ち続けたりパニックして世界がエラーとなったりGoの糸電話は怖い印象。また上記はバッファ無しのチャネルのケース。バッファ有りの場合は「X個までしか同時に桃を流せない川」というイメージだろうか。
この記事が気に入ったらサポートをしてみませんか?