在golang中,len()函数是否支持线程安全?

10
我正在记录map的长度,每秒一次;我不在乎是否有“精确”值/竞争条件(偏差为1是可以接受的)。我想知道这是否会导致panic,并且我是否必须用一些.RLock()/Unlock()来包含len()。
我之所以问是因为在map中进行并发读/写会导致panic(Go会检测到),但我不知道读取长度是否算作“读取”。我已经用测试程序尝试过了,但无法产生崩溃,但至少为了安全起见,我宁愿得到一个确切的答案。
如果有关数组和映射的长度,那么这很重要。谢谢!

3
数组的长度是编译时常量,因此是线程安全的。如果您想询问切片的长度,则答案是否定的。 - Charlie Tumahai
是的,抱歉我是指切片。 - Thomas
2个回答

9
这是一种竞态条件,结果是未定义的。例如, :
package main

func main() {
    m := make(map[int]int)
    l := 0
    go func() {
        for {
            l = len(m)
        }
    }()
    for i := 0; i < 10000; i++ {
        m[i] = i
    }
}

输出:

$ go run -race racer.go
==================
WARNING: DATA RACE
Read at 0x00c00008e000 by goroutine 5:
  main.main.func1()
      /home/peter/gopath/src/racer.go:8 +0x5f

Previous write at 0x00c00008e000 by main goroutine:
  runtime.mapassign_fast64()
      /home/peter/go/src/runtime/map_fast64.go:92 +0x0
  main.main()
      /home/peter/gopath/src/racer.go:12 +0xba

Goroutine 5 (running) created at:
  main.main()
      /home/peter/gopath/src/racer.go:6 +0x92
==================
Found 1 data race(s)
exit status 66
$

参考资料:

维基百科: 赛事状态

Go博客: 介绍Go赛事探测器

Go: 数据竞争探测器

良性数据竞争: 可能出现什么问题?


1
所以这是一个对答案精确度的竞赛,但如果我只对“可接受值”感兴趣,而不会出现恐慌(例如在地图中读取/写入),那么可以吗? - Thomas
1
@Thomas:数据竞争的结果是未定义的。不要这样做!请参考我的引用了解“良性”数据竞争的危害。 - peterSO

0

如果您接受 len() 的脏数据,该操作将不会导致死锁,并且不会引起任何恐慌。

我在以下情况下遇到了这个问题:我需要通过判断 map 的长度是否达到限制来决定是否清理过期的数据。但是我不需要精确限制 map 的大小,因为写操作被 .Lock()/Unlock() 包围,并且也会检查限制。

希望这种情况能帮助您。然而,如果 len() 不是高频调用,我认为将其与锁一起封装更好。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接