golang sync.Map Range函数线程安全吗?

From the doc

Range does not necessarily correspond to any consistent snapshot of the 
Map's contents: no key will be visited more than once, but if the value 
for any key is stored or deleted concurrently, Range may reflect any 
mapping for that key from any point during the Range call.

Does this mean that no read lock is invoked during range call and user must implements his own mutex in order for Range call to be thread safe?

You hit it pretty spot on.

Basically, this works the same way you'd use for: You're just grabbing a count up front, and then iterating each value you expect to exist.

Ideally, if you have to worry about concurrency on the map, you should make a copy that you then iterate, or implement a sync.Mutex around it.

Read all the documentation, including this part.

Package sync

import "sync"

type Map 1.9

Map is like a Go map[interface{}]interface{} but is safe for concurrent use by multiple goroutines without additional locking or coordination. Loads, stores, and deletes run in amortized constant time.

The Map type is specialized. Most code should use a plain Go map instead, with separate locking or coordination, for better type safety and to make it easier to maintain other invariants along with the map content.

The Map type is optimized for two common use cases: (1) when the entry for a given key is only ever written once but read many times, as in caches that only grow, or (2) when multiple goroutines read, write, and overwrite entries for disjoint sets of keys. In these two cases, use of a Map may significantly reduce lock contention compared to a Go map paired with a separate Mutex or RWMutex.


By design, sync.Map is thread safe. sync.Map is a special purpose map with limited uses.

Most code should use a plain Go map instead, with separate locking or coordination, for better type safety and to make it easier to maintain other invariants along with the map content.

Don't add an additional layer of locking to sync.Map. Use a different algorithm or follow advice and use a plain Go map with separate locking or coordination.


Package sync

import "sync"

func (*Map) Range 1.9

func (m *Map) Range(f func(key, value interface{}) bool)

Range calls f sequentially for each key and value present in the map. If f returns false, range stops the iteration.

Range does not necessarily correspond to any consistent snapshot of the Map's contents: no key will be visited more than once, but if the value for any key is stored or deleted concurrently, Range may reflect any mapping for that key from any point during the Range call.

Range may be O(N) with the number of elements in the map even if f returns false after a constant number of calls.


The weak invariants on sync.Map Range mean that it's often not very useful.