Golang 中的 slice 為什么是并發(fā)不安全的?
一、并發(fā)不安全的
??在Go語(yǔ)言中,slice是并發(fā)不安全的,主要有以下兩個(gè)原因:數(shù)據(jù)競(jìng)爭(zhēng)、內(nèi)存重分配。
??數(shù)據(jù)競(jìng)爭(zhēng):slice底層的結(jié)構(gòu)體包含一個(gè)指向底層數(shù)組的指針和該數(shù)組的長(zhǎng)度,當(dāng)多個(gè)協(xié)程并發(fā)訪(fǎng)問(wèn)同一個(gè)slice時(shí),有可能會(huì)出現(xiàn)數(shù)據(jù)競(jìng)爭(zhēng)的問(wèn)題。例如,一個(gè)協(xié)程在修改slice的長(zhǎng)度,而另一個(gè)協(xié)程同時(shí)在讀取或修改slice的內(nèi)容。
??內(nèi)存重分配:在向slice中追加元素時(shí),可能會(huì)觸發(fā)slice的擴(kuò)容操作,在這個(gè)過(guò)程中,如果有其他協(xié)程訪(fǎng)問(wèn)了slice,就會(huì)導(dǎo)致指向底層數(shù)組的指針出現(xiàn)異常。
二、并發(fā)場(chǎng)景
??多個(gè)協(xié)程同時(shí)向 slice 追加元素,會(huì)有一部分元素被追加到了舊的底層數(shù)組里,最終 slice 的長(zhǎng)度小于目標(biāo)值。
func main() {
a := make([]int, 0)
for i := 0; i < 10000; i++ {
go func(i int) {
a = append(a, i)
}(i)
}
fmt.Println(len(a)) // 9015 < 10000
}
三、實(shí)現(xiàn) slice 并發(fā)安全
??要實(shí)現(xiàn) slice 并發(fā)安全,有兩種方法:加互斥鎖、使用channel串行化操作。
方式一:使用互斥鎖 sync.Mutex
??追加元素之前調(diào)用 Lock() 函數(shù)加鎖,追加完后,調(diào)用 Unlock() 解鎖。
func main() {
var lock sync.Mutex //互斥鎖
a := make([]int, 0)
var wg sync.WaitGroup
for i := 0; i < 10000; i++ {
wg.Add(1)
go func(i int) {
defer wg.Done()
lock.Lock()
defer lock.Unlock()
a = append(a, i)
}(i)
}
wg.Wait()
fmt.Println(len(a))
// equal 10000
}
最終 slice 的長(zhǎng)度等于目標(biāo)值。
方式二:使用channel串行化操作
??生產(chǎn)者生產(chǎn)元素,發(fā)送到通道中,消費(fèi)者從通道中接收元素,追加到 slice 中。使用無(wú)緩沖通道,接收方、發(fā)送方必須同時(shí)存在,負(fù)責(zé)任意一方都會(huì)阻塞。
func main() {
buffer := make(chan int)
a := make([]int, 0)
// 消費(fèi)者
go func() {
for v := range buffer {
a = append(a, v)
}
}()
// 生產(chǎn)者
var wg sync.WaitGroup
for i := 0; i < 10000; i++ {
wg.Add(1)
go func(i int) {
defer wg.Done()
buffer <- i
}(i)
}
wg.Wait()
fmt.Println(len(a))
// equal 10000
}
最終 slice 的長(zhǎng)度等于目標(biāo)值。
文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-753337.html
兩種方式的比較
??加互斥鎖適合于對(duì)性能要求不高的場(chǎng)景,畢竟鎖的粒度太大,這種方式屬于通過(guò)共享內(nèi)存來(lái)實(shí)現(xiàn)通信。channle 適合于對(duì)性能要求大的場(chǎng)景,channle 就是專(zhuān)用于 goroutine 間通信的,這種方式屬于通過(guò)通信來(lái)實(shí)現(xiàn)共享內(nèi)存。文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-753337.html
到了這里,關(guān)于Golang 中的 slice 為什么是并發(fā)不安全的?的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!