數(shù)據(jù)競爭和內存重分配Golang slice并發(fā)不安全問題解決
Golang 中的 slice 為什么是并發(fā)不安全的?
一、并發(fā)不安全的
在Go語言中,slice是并發(fā)不安全的,主要有以下兩個原因:數(shù)據(jù)競爭、內存重分配。
數(shù)據(jù)競爭:slice底層的結構體包含一個指向底層數(shù)組的指針和該數(shù)組的長度,當多個協(xié)程并發(fā)訪問同一個slice時,有可能會出現(xiàn)數(shù)據(jù)競爭的問題。例如,一個協(xié)程在修改slice的長度,而另一個協(xié)程同時在讀取或修改slice的內容。
內存重分配:在向slice中追加元素時,可能會觸發(fā)slice的擴容操作,在這個過程中,如果有其他協(xié)程訪問了slice,就會導致指向底層數(shù)組的指針出現(xiàn)異常。
二、并發(fā)場景
多個協(xié)程同時向 slice 追加元素,會有一部分元素被追加到了舊的底層數(shù)組里,最終 slice 的長度小于目標值。
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
}三、實現(xiàn) slice 并發(fā)安全
要實現(xiàn) slice 并發(fā)安全,有兩種方法:加互斥鎖、使用channel串行化操作。
方式一:使用互斥鎖 sync.Mutex
追加元素之前調用 Lock() 函數(shù)加鎖,追加完后,調用 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 的長度等于目標值。
方式二:使用channel串行化操作
生產者生產元素,發(fā)送到通道中,消費者從通道中接收元素,追加到 slice 中。使用無緩沖通道,接收方、發(fā)送方必須同時存在,負責任意一方都會阻塞。
func main() {
buffer := make(chan int)
a := make([]int, 0)
// 消費者
go func() {
for v := range buffer {
a = append(a, v)
}
}()
// 生產者
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 的長度等于目標值。
兩種方式的比較
加互斥鎖適合于對性能要求不高的場景,畢竟鎖的粒度太大,這種方式屬于通過共享內存來實現(xiàn)通信。channle 適合于對性能要求大的場景,channle 就是專用于 goroutine 間通信的,這種方式屬于通過通信來實現(xiàn)共享內存。
以上就是數(shù)據(jù)競爭和內存重分配Golang slice并發(fā)不安全問題解決的詳細內容,更多關于Golang slice并發(fā)安全的資料請關注腳本之家其它相關文章!
相關文章
Golang中實現(xiàn)類似類與繼承的方法(示例代碼)
這篇文章主要介紹了Golang中實現(xiàn)類似類與繼承的方法,Go語言中通過方法接受者的類型來決定方法的歸屬和繼承關系,本文通過示例代碼講解的非常詳細,需要的朋友可以參考下2024-04-04
如何將Golang數(shù)組slice轉為逗號分隔的string字符串
這篇文章主要介紹了如何將Golang數(shù)組slice轉為逗號分隔的string字符串問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2023-09-09
Go語言的WebAssembly實戰(zhàn)開發(fā)
Go語言的WebAssembly支持為Web開發(fā)帶來了新的可能性,本文主要介紹了Go語言與WebAssembly的結合,內容包括編譯方法、JavaScript交互、性能優(yōu)化技巧和實戰(zhàn)案例,感興趣的可以了解一下2026-05-05
Golang中crypto/ecdsa庫實現(xiàn)數(shù)字簽名和驗證
本文主要介紹了Golang中crypto/ecdsa庫實現(xiàn)數(shù)字簽名和驗證,將從ECDSA的基本原理出發(fā),詳細解析如何在Go語言中實現(xiàn)數(shù)字簽名和驗證,具有一定的參考價值,感興趣的可以了解一下2024-02-02

