New Chat
Ctrl
K
Chat History
Mobile App

Go中线程不安全的数据类型

上下文:Go 程序开发。 指令:哪些数据类型存在线程不安全?读写都不安全吗
在 Go 程序里,只有下面几类数据类型是明确线程不安全的:
  1. 切片(slice)
  2. 字典(map)
  3. 字符串(string)
  4. 接口值(interface{} 的动态字面值)
  5. 通道(channel)——仅对 “关闭” 操作 与其他操作并发时是安全的;对同一个 channel 做并发写/读本身是安全的,但并发关闭与关闭后继续使用是未定义行为。
  6. 结构体/数组等聚合类型里含有上述类型字段时,整体也变成“非原子”。
除此之外的内建类型(int、float、bool、指针、array、struct 里全是简单值类型等)在按值使用时都是线程安全的,因为它们在赋值/传参时会被完整复制;然而一旦通过指针共享内存,它们的读/写就可能出现数据竞争,需要显式同步。

读写是否都不安全?

Table
Copy
类型读并发写并发读写并发备注
slice不安全不安全不安全grow、append 都可能搬迁底层数组
map不安全不安全不安全任何并发访问都会触发 fatal error
string不安全不安全不安全string header 含指针和 len,非原子
interface不安全不安全不安全动态值和类型字面值双字结构
channel安全安全安全仅 close(ch) 与其他操作并发不安全

一句话总结

在 Go 里,只要两个 goroutine 对同一块内存进行写操作,或一个 goroutine 写、另一个 goroutine 读,都需要同步。
内建类型本身没有“锁”,因此除 channel 外,所有通过指针共享的数据(包括 map、slice、string、interface、自定义结构体等)都必须在并发访问时加锁或采用其他同步手段(sync.Mutex/RWMutex、sync/atomic、chan 等)。