在 Go 语言中,切片(slice)本身并不是线程安全的。虽然切片的数据结构本身是简单的,包含指向底层数组的指针、长度和容量,但当多个 goroutine 同时读写同一个切片时,就会出现数据竞争(data race)的问题。
线程安全的切片使用建议
- 互斥锁:如果多个 goroutine 需要对同一个切片进行读写操作,可以使用
sync.Mutex
或sync.RWMutex
来保护对切片的访问,以确保在某一时刻只有一个 goroutine 可以对切片进行修改。
package main
import (
"fmt"
"sync"
)
var (
mu sync.Mutex
slice []int
)
func addToSlice(val int, wg *sync.WaitGroup) {
defer wg.Done()
mu.Lock() // 锁定
slice = append(slice, val)
mu.Unlock() // 解锁
}
func main() {
var wg sync.WaitGroup
for i := 0; i < 10; i++ {
wg.Add(1)
go addToSlice(i, &wg)
}
wg.Wait()
fmt.Println(slice)
}
只读操作:如果只需要从切片中读取数据,而不修改它,那么可以安全地在多个 goroutine 中并发读取。
复制切片:如果可能的话,可以将原始切片复制到新的切片,然后在新的 goroutine 中处理副本,这样可以避免直接竞争。
通道(Channels):利用 Go 的通道来协调不同 goroutine 的工作,也是一种常见且优雅的方式。例如,你可以通过通道发送值而不是直接操作共享的切片。
总结
总之,在 Go 中,默认情况下,切片不是线程安全的。当需要在多个 goroutine 间共享和修改切片时,需要采取适当的方法来保证同步,例如使用互斥锁、通道等。
内容由零声教学AI助手提供,问题来源于学员提问