Go保證并發(fā)安全底層實現(xiàn)詳解
引言
上一部分主要寫了鎖,本篇主要介紹Channel
channel是Go中非常重要的一個數(shù)據(jù)類型,它和goroutine緊密相連,是Go的CSP并發(fā)模型的重要體現(xiàn)。
CSP
- CSP 是通信順序進(jìn)程(Communicating Sequential Process)的簡稱,是一種并發(fā)編程模型。
- 簡單來說,CSP模型由并發(fā)的實體所組成,實體之間通過發(fā)送消息進(jìn)行通信,而發(fā)送消息使用的就是通道,即channel。
- GO實現(xiàn)了CSP部分理論,goroutine對應(yīng)CSP中的并發(fā)執(zhí)行的實體,channel對應(yīng)CSP中的channel。
不要通過共享內(nèi)存來通信,而應(yīng)該通過通信來共享內(nèi)存
Channel的基本使用
package main
import "fmt"
func main() {
c := make(chan int)
go func() {
c <- 1 // 向channel發(fā)送數(shù)據(jù)
}()
x := <-c // 從channel中接收數(shù)據(jù)
fmt.Println(x)
}
1、通過make(chan int)創(chuàng)建一個int channel(可以在channel初始化時指定緩沖區(qū)的大小,例如make(chan int,2),不指定則默認(rèn)為0)
2、在一個goroutine中,通過c<-1將數(shù)據(jù)發(fā)送到channel中,<-可以理解為數(shù)據(jù)的流動方向。
3、在主goroutine中通過x := <-c接收channel中的數(shù)據(jù),并賦值給x。
channel如何保證并發(fā)安全
既然goroutin和channel分別對應(yīng)csp中的實體和媒介,goroutin之間都是通過chennel來傳遞數(shù)據(jù),那么是如何保證并發(fā)安全的呢?
通過閱讀源碼可以發(fā)現(xiàn),channel內(nèi)部是使用Mutext互斥鎖來保證的( 之前也有人提出CAS無鎖Channel的實現(xiàn),但因為無鎖Channel在多核測試中的表現(xiàn)和沒有滿足FIFO的特性等原因,該提案目前是擱淺狀態(tài))關(guān)于無鎖channel的討論
channel的底層實現(xiàn)
channel的核心源碼位于runtime包的chan.go中。
hchan 是 channel 在 golang 中的內(nèi)部實現(xiàn)
type hchan struct {
qcount uint // total data in the queue
dataqsiz uint // size of the circular queue
buf unsafe.Pointer // points to an array of dataqsiz elements
elemsize uint16
closed uint32
elemtype *_type // element type
sendx uint // send index
recvx uint // receive index
recvq waitq // list of recv waiters
sendq waitq // list of send waiters
// lock protects all fields in hchan, as well as several
// fields in sudogs blocked on this channel.
//
// Do not change another G's status while holding this lock
// (in particular, do not ready a G), as this can deadlock
// with stack shrinking.
lock mutex
}
hchan的所有屬性大體可以分為3類
1、buffer相關(guān)屬性,當(dāng)channel中的緩沖區(qū)大小不為0時,buffer中存放了待接收的數(shù)據(jù)。
2、waitq相關(guān)屬性,即recvq和sendq,可以理解為一個標(biāo)準(zhǔn)的FIFO隊列,recvq是等待接收數(shù)據(jù)的goroutine,sendq是等待發(fā)送數(shù)據(jù)的goroutine。
3、其它,例如lock(互斥鎖)、elemtype(元素類型)、closed(channel 是否關(guān)閉,== 0 代表未 closed)
hchan的所有行為,基本都是圍繞buffer和waitq來實現(xiàn)的
waitq
type waitq struct {
first *sudog
last *sudog
}
waitq是一個雙向鏈表,里面保存了goroutine。
buffe
buffer使用 ring buffer(環(huán)形緩沖區(qū))實現(xiàn)
在hchan中,可以看到 recvx和sendx 兩個屬性,recvx即當(dāng)前已發(fā)送的元素在隊列當(dāng)中的索引位置,sendx 即 當(dāng)前已接收的元素在隊列當(dāng)中的索引位置。
從 recvx 到 sendx 之間的元素,表示已正常存放入 buffer 中的數(shù)據(jù)。
Lock
hchan中的lock就是一個互斥鎖,channel在發(fā)送和接收數(shù)據(jù)前,都會先進(jìn)行加鎖,待邏輯完成后執(zhí)行再解鎖,來保證并發(fā)安全。
以上就是Go保證并發(fā)安全底層實現(xiàn)詳解的詳細(xì)內(nèi)容,更多關(guān)于Go并發(fā)安全底層實現(xiàn)的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
golang實現(xiàn)webgis后端開發(fā)的步驟詳解
Go語言中函數(shù)可變參數(shù)(Variadic Parameter)詳解
一文理解Goland協(xié)程調(diào)度器scheduler的實現(xiàn)
Golang簡單實現(xiàn)http的server端和client端

