map不是并发安全的 官方的faq 里有说明,考虑到有性能损失,map没有设计成原子操作,在并发读写时会有问题。
Map access is unsafe only when updates are occurring. As long as all goroutines are only reading—looking up elements in the map, including iterating through it using a for range loop—and not changing the map by assigning to elements or doing deletions, it is safe for them to access the map concurrently without synchronization.
 
 
查看源码,进一步立即实现机制
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 const (   ...  	hashWriting  = 4   	...  ) type  hmap struct {	...  	flags     uint8 	...  } map 是检查是否有另外线程修改h.flag来判断,是否有并发问题。	if  h.flags&hashWriting == 0  { 		throw("concurrent map writes" ) 	} 	 	if  h.flags&hashWriting != 0  { 		throw("concurrent map read and map write" ) 	} 
 
测试并发问题的例子:一个goroutine不停地写,另一个goroutine不停地读
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 package  mainimport  (	"fmt"  	"time"  ) func  main ()   {	c := make (map [string ]int ) 	go  func ()   {  		for  j := 0 ; j < 1000000 ; j++ { 			c[fmt.Sprintf("%d" , j)] = j 		} 	}() 	go  func ()   {  		for  j := 0 ; j < 1000000 ; j++ { 			fmt.Println(c[fmt.Sprintf("%d" , j)]) 		} 	}() 	time.Sleep(time.Second * 20 ) } 
 
立马产生错误
1 2 3 4 5 6 7 8 9 0 fatal error: concurrent map read  and map write  goroutine 19  [running]: runtime .throw (0 x10d6ea4, 0 x21)        /usr/ local/go/ src/runtime/ panic.go:774  +0 x72 fp=0 xc00009aef0 sp=0 xc00009aec0 pc=0 x10299c2 runtime .mapaccess1_faststr(0 x10b41e0, 0 xc000066180, 0 x116ae71, 0 x1, 0 x1)        /usr/ local/go/ src/runtime/m ap_faststr.go:21  +0 x44f fp=0 xc00009af60 sp=0 xc00009aef0 pc=0 x100ffff main.main.func2(0 xc000066180) 
 
This statement declares a counter variable that is an anonymous struct containing a map and an embedded sync.RWMutex.
1 2 3 4 var  counter = struct {    sync.RWMutex     m map [string ]int  }{m: make (map [string ]int )} 
 
To read from the counter, take the read lock:
1 2 3 4 counter.RLock () n := counter.m ["some_key" ]  counter.RUnlock () fmt.Println ("some_key:" , n) 
 
To write to the counter, take the write lock:
1 2 3 counter.Lock () counter.m ["some_key" ] ++ counter.Unlock () 
 
针对上面有并发问题的测试例子,可以修改成以下代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 package  mainimport  (	"fmt"  	"sync"  	"time"  ) func  main ()   {	var  c = struct  { 		sync.RWMutex 		m map [string ]int  	}{m: make (map [string ]int )} 	go  func ()   {  		for  j := 0 ; j < 1000000 ; j++ { 			c.Lock() 			c.m[fmt.Sprintf("%d" , j)] = j 			c.Unlock() 		} 	}() 	go  func ()   {  		for  j := 0 ; j < 1000000 ; j++ { 			c.RLock() 			fmt.Println(c.m[fmt.Sprintf("%d" , j)]) 			c.RUnlock() 		} 	}() 	time.Sleep(time.Second * 20 ) } 
 
sync.Map sync.Map 是官方出品的并发安全的 map,他在内部使用了大量的原子操作来存取键和值,并使用了 read 和 dirty 二个原生 map 作为存储介质,具体实现流程可阅读相关源码。
参考:
https://learnku.com/articles/27691 
参考链接 
The Go Blog - Go maps in action 
 
Why are map operations not defined to be atomic?