go routineのスレッド間でデータを共有する
※本記事は備忘録として記載したものでありますため、ご容赦ください。
goroutineで動作している関数でデータを共有するには、
- 引数として渡す方法
- クロージャのローカル変数にキャプチャして渡す方法
があります。
package main
import (
"fmt"
"time"
)
func sub1(c int) {
fmt.Println("share by arguments : ", c*c)
}
func main() {
// 引数で渡す方法
go sub1(10)
// クロージャのキャプチャで渡す方法
c := 20
go func() {
fmt.Println("share by capture : ", c*c)
}()
time.Sleep(time.Second)
}
# 結果
share by arguments : 100
share by capture : 400
クロージャのキャプチャ渡しの場合も、内部的には無名関数に引数が追加されて参照が渡されるため、厳密には同じ動きとなります。
forを使用してみる
package main
import (
"fmt"
"time"
)
func main() {
tasks := []string{
"cmake ..",
"cmake . --build release",
"cpack",
}
for _, task := range tasks {
go func() {
// goroutineが起動する時にはループが回り切って
// 全部のtaskが最後のタスクになってしまう
fmt.Println(task)
}()
}
time.Sleep(time.Second)
}
# 結果
cpack
cpack
cpack
高速ではありますが、単純なループに比べてgoroutineの起動が遅いため、taskに"cpack"が入った状態でループが回ってしまう。
このような場合は、引数経由にして明示的に値をコントロールするべきです。
子goroutineから親goroutineへの値渡し
両者は共有アドレスを参照しているため、上書きに注意が必要です。
参考