共有メモリによる通信
- 共有メモリを使うパターンはシンプル
- しかしデータの競合に気を使う必要がある
素朴な (しかし悪い) 例
- 何も考えずに共有メモリを使ってみたパターン
- 配列を goroutine 使ってじゃんじゃん伸ばしていきたいとする
- 以下を実行するとどうなるでしょうか (playground)
package main
import (
"fmt"
"time"
)
func main() {
ints := []int{}
for i := 0; i < 10; i++ {
go func(n int) {
ints = append(ints, n)
}(i)
}
time.Sleep(time.Second)
fmt.Println(ints)
}
- (playground で動かすとうまく動いちゃう…)
- やるたびに結果が変わるはず
- 各 goroutine は
ints
を読み込んで新しい値を入れて上書きしようとする
- 読み込んで上書きしようとする間に別の goroutine によって値が更新されてしまう
修正案 (1) sync.Mutex による排他制御
- 素朴に
sync.Mutex
を使って排他制御を行う
- とりあえずシンプルで悪くない (個人の感想です)
package main
import (
"fmt"
"sync"
"time"
)
func main() {
ints := []int{}
mu := sync.Mutex{}
for i := 0; i < 10; i++ {
go func(n int) {
mu.Lock()
ints = append(ints, n)
mu.Unlock()
}(i)
}
time.Sleep(time.Second)
fmt.Println(ints)
}
修正案 (2) 並列処理せず、直列にする
- 身も蓋もないが、そもそも直列にすればええやん、ということもある
- 以下、goroutine 使うの辞めた場合
package main
import (
"fmt"
)
func main() {
ints := []int{}
for i := 0; i < 10; i++ {
ints = append(ints, n)
}
fmt.Println(ints)
}