As said above, maps are not safe inside go routines like this.
The simplest way to modify your example is to add a mutex and perform lock/unlock on each pass.
package main
import (
"fmt"
"sync"
)
type Counter struct {
m map[string]int
mu sync.Mutex
}
func main() {
counter := Counter{m: make(map[string]int)}
var wg sync.WaitGroup
for i := 0; i < 100; i++ {
wg.Add(1)
go func(id int) {
defer wg.Done()
key := fmt.Sprintf("key%d", id)
counter.mu.Lock()
defer counter.mu.Unlock()
counter.m[key] = id * 10
}(i)
}
wg.Wait()
fmt.Println(counter.m)
}
This should help demonstrate the issue. But there are other ways to handle this, with read/write mutex or a channel. Note that using locks may slow down the program, compared to other methods.
More discussion: How safe are Golang maps for concurrent Read/Write operations?