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

时间:2019-01-14 00:53:08

标签: go

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.

这是否意味着在范围调用期间不会调用任何读取锁定,并且用户必须实现自己的互斥体才能使Range调用成为线程安全的?

2 个答案:

答案 0 :(得分:2)

阅读所有文档,包括本部分。

  

Package sync

     

导入“同步”

     

type Map 1.9

     

地图就像Go地图[interface {}] interface {},但对于   由多个goroutine并发使用,而无需额外的锁定或   协调。加载,存储和删除以摊销常量运行   时间。

     

地图类型是专用的。大多数代码应使用普通的Go地图   相反,具有单独的锁定或协调功能,以提高类型安全性   并使其更易于维护其他不变式和地图   内容。

     

Map类型针对两种常见用例进行了优化:(1)输入   对于给定的密钥,只能写入一次但可以读取多次,例如   仅增长的缓存,或者(2)当多个goroutine进行读取,写入,   并覆盖不相交的键集的条目。在这两种情况下,   与Go相比,使用Map可以显着减少锁争用   地图与单独的Mutex或RWMutex配对。


根据设计,sync.Map是线程安全的。 sync.Map是用途有限的专用地图。

  

大多数代码应改用纯Go映射,并使用单独的锁定或   协调,以更好地保护类型并使其易于维护   其他不变式以及地图内容。

请勿在{{1​​}}上添加额外的锁定层。使用其他算法或遵循建议,并使用带有单独锁定或协调功能的简单Go sync.Map


  

Package sync

     

导入“同步”

     

func(* Map)范围1.9

map
     

范围会依次针对地图中存在的每个键和值调用f。   如果f返回false,则range停止迭代。

     

范围不一定对应于任何一致的快照   地图内容:不会多次访问任何键,但是如果   并发存储或删除任何键的值,范围可能反映   在Range调用期间从任何点对该键的任何映射。

     

范围可能是O(N),且映射中的元素数量即使f   一定数量的调用后返回false。


func (m *Map) Range(f func(key, value interface{}) bool) sync.Map上的弱不变式意味着它通常不是很有用。

答案 1 :(得分:0)

你击中了它。

基本上,这与您使用for的方式相同:您只是先获取一个计数,然后迭代您希望存在的每个值。

理想情况下,如果您必须担心地图上的并发性,则应制作一个副本,然后对其进行迭代,或在其周围实现一个sync.Mutex