errgroup
パッケージの使い方はあっています。上記のコードはローカル環境でコンパイルできましたか?(条件
や m に追加
などを想定通り記述した上で)
以下は上記のコードに少しだけ手入れして、動作するようにしたコード例です。
go
1package main
2
3import (
4 "fmt"
5 "strconv"
6 "sync"
7
8 "golang.org/x/sync/errgroup"
9)
10
11func main() {
12 var mu sync.Mutex
13 eg := errgroup.Group{}
14 m := make(map[string][]string)
15 for i := 0; i < 10; i++ {
16 i := i
17 eg.Go(func() error {
18 mu.Lock()
19 m[strconv.Itoa(i)] = []string{strconv.Itoa(i * 100)}
20 mu.Unlock()
21 return nil
22 })
23 }
24 eg.Wait()
25
26 fmt.Printf("m: %+v", m)
27}
https://play.golang.org/p/EgRFZxCWyVE
m: map[0:[0] 1:[100] 2:[200] 3:[300] 4:[400] 5:[500] 6:[600] 7:[700] 8:[800] 9:[900]]
追記
for loop上の変数をgoroutineで並行処理する場合には注意が必要です。以下のコードは正しく動きません。
go
1package main
2
3import (
4 "fmt"
5
6 "golang.org/x/sync/errgroup"
7)
8
9func main() {
10 g := errgroup.Group{}
11 s := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
12
13 for _, v := range s {
14 // v := v としてループごとに独立したアドレスで値を確保する必要があります
15 g.Go(func() error {
16 fmt.Printf("value: %d\n", v)
17 return nil
18 })
19 }
20
21 g.Wait()
22}
上記の for range 内で宣言している値のアドレスはループごとに独立ではなく、 同じ アドレスを共有しています。そして、それぞれのgoroutineではクロージャで変数の "アドレス" を参照しています。つまりgoroutineで変数の値を参照するときに競合状態になっています。
ループごとの独立した変数のアドレスを確保しなおす必要があります。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2020/09/24 11:40
2020/09/24 11:56
2020/09/24 12:52
2020/09/24 12:56
2020/09/24 21:15
2020/09/25 10:19
2020/09/25 11:44 編集
2020/09/25 12:38