为了账号安全,请及时绑定邮箱和手机立即绑定

在Go中使用范围获取值不是线程安全的吗?

在Go中使用范围获取值不是线程安全的吗?

Go
POPMUISE 2021-05-06 10:02:07
当在m具有并发编写器的地图(包括可能会从该地图中删除的写入器)上进行遍历时,这样做不是线程安全的吗?for k, v := range m { ... }我以为是线程安全的,因此我需要防止其他可能的编写者v在读取值时更改其值,并且(在使用互斥锁且由于锁定是一个单独的步骤时)请验证键k是否仍在映射中。例如:for k := range m {    m.mutex.RLock()    v, found := m[k]    m.mutex.RUnlock()    if found {        ... // process v    }}(假设其他作者m在更改之前处于写锁定状态v。)是否有更好的方法?编辑添加:我知道映射不是线程安全的。但是,根据http://golang.org/ref/spec#For_statements上的Go规范,它们以一种方式是线程安全的(搜索“如果在迭代过程中删除了尚未到达的映射条目”)。此页面表明,使用的代码range无需担心其他goroutine插入到地图或从地图删除的情况。我的问题是,此线程安全性是否扩展到v,这样我v 只能使用for k, v := range m并没有其他线程安全机制?我创建了一些测试代码来试图迫使应用程序崩溃以证明它不起作用,但是即使运行公然线程不安全的代码(很多goroutine在没有适当的锁定机制的情况下疯狂地修改了相同的映射值)进入崩溃!
查看完整描述

2 回答

?
温温酱

TA贡献1752条经验 获得超4个赞

否,地图操作不是原子/线程安全的,因为您的问题的评论者指出了golang FAQ“为什么地图操作未定义为原子的?” 。

为了确保您的访问安全,建议您使用Go的频道作为资源访问令牌的一种方式。该通道用于简单地传递令牌。任何想要修改它的人都会从渠道请求-阻止或非阻止。处理完地图后,它将令牌传递回通道。

遍历和使用地图应该足够简单且简短,因此您应该可以只使用一个令牌进行完全访问。

如果不是这种情况,并且您将地图用于更复杂的东西/资源消耗者需要更多时间,则可以实现读写器访问令牌。因此,在任何给定时间,只有一个编写者可以访问该地图,但是当没有任何编写者处于活动状态时,令牌将传递给任意数量的读取者,而这些读取者不会修改该映射(因此他们可以同时读取)。


查看完整回答
反对 回复 2021-05-17
?
慕尼黑8549860

TA贡献1818条经验 获得超11个赞

您可以使用并发映射为您处理并发难题。


// Create a new map.

map := cmap.NewConcurretMap()


// Add item to map, adds "bar" under key "foo"

map.Add("foo", "bar")


// Retrieve item from map.

tmp, ok := map.Get("foo")


// Checks if item exists

if ok == true {

    // Map stores items as interface{}, hence we'll have to cast.

    bar := tmp.(string)

}


// Removes item under key "foo"

map.Remove("foo")


查看完整回答
反对 回复 2021-05-17
  • 2 回答
  • 0 关注
  • 160 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信