Go保證并發(fā)安全底層實(shí)現(xiàn)詳解
引言
上一部分主要寫了鎖,本篇主要介紹Channel
channel是Go中非常重要的一個(gè)數(shù)據(jù)類型,它和goroutine緊密相連,是Go的CSP并發(fā)模型的重要體現(xiàn)。
CSP
- CSP 是通信順序進(jìn)程(Communicating Sequential Process)的簡稱,是一種并發(fā)編程模型。
- 簡單來說,CSP模型由并發(fā)的實(shí)體所組成,實(shí)體之間通過發(fā)送消息進(jìn)行通信,而發(fā)送消息使用的就是通道,即channel。
- GO實(shí)現(xiàn)了CSP部分理論,goroutine對應(yīng)CSP中的并發(fā)執(zhí)行的實(shí)體,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)建一個(gè)int channel(可以在channel初始化時(shí)指定緩沖區(qū)的大小,例如make(chan int,2)
,不指定則默認(rèn)為0)
2、在一個(gè)goroutine中,通過c<-1
將數(shù)據(jù)發(fā)送到channel中,<-
可以理解為數(shù)據(jù)的流動(dòng)方向。
3、在主goroutine中通過x := <-c
接收channel中的數(shù)據(jù),并賦值給x。
channel如何保證并發(fā)安全
既然goroutin和channel分別對應(yīng)csp中的實(shí)體和媒介,goroutin之間都是通過chennel來傳遞數(shù)據(jù),那么是如何保證并發(fā)安全的呢?
通過閱讀源碼可以發(fā)現(xiàn),channel內(nèi)部是使用Mutext互斥鎖來保證的( 之前也有人提出CAS無鎖Channel的實(shí)現(xiàn),但因?yàn)闊o鎖Channel在多核測試中的表現(xiàn)和沒有滿足FIFO的特性等原因,該提案目前是擱淺狀態(tài))關(guān)于無鎖channel的討論
channel的底層實(shí)現(xiàn)
channel的核心源碼位于runtime包的chan.go中。
hchan 是 channel 在 golang 中的內(nèi)部實(shí)現(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時(shí),buffer中存放了待接收的數(shù)據(jù)。
2、waitq相關(guān)屬性,即recvq和sendq,可以理解為一個(gè)標(biāo)準(zhǔn)的FIFO隊(duì)列,recvq是等待接收數(shù)據(jù)的goroutine,sendq是等待發(fā)送數(shù)據(jù)的goroutine。
3、其它,例如lock(互斥鎖)、elemtype(元素類型)、closed(channel 是否關(guān)閉,== 0 代表未 closed)
hchan的所有行為,基本都是圍繞buffer和waitq來實(shí)現(xiàn)的
waitq
type waitq struct { first *sudog last *sudog }
waitq是一個(gè)雙向鏈表,里面保存了goroutine。
buffe
buffer使用 ring buffer(環(huán)形緩沖區(qū))實(shí)現(xiàn)
在hchan中,可以看到 recvx
和sendx
兩個(gè)屬性,recvx
即當(dāng)前已發(fā)送的元素在隊(duì)列當(dāng)中的索引位置,sendx
即 當(dāng)前已接收的元素在隊(duì)列當(dāng)中的索引位置。
從 recvx
到 sendx
之間的元素,表示已正常存放入 buffer 中的數(shù)據(jù)。
Lock
hchan中的lock
就是一個(gè)互斥鎖,channel在發(fā)送和接收數(shù)據(jù)前,都會先進(jìn)行加鎖,待邏輯完成后執(zhí)行再解鎖,來保證并發(fā)安全。
以上就是Go保證并發(fā)安全底層實(shí)現(xiàn)詳解的詳細(xì)內(nèi)容,更多關(guān)于Go并發(fā)安全底層實(shí)現(xiàn)的資料請關(guān)注腳本之家其它相關(guān)文章!
- Go類型斷言提取測試接口值動(dòng)態(tài)類型及靜態(tài)轉(zhuǎn)換確保類型接口編譯安全
- 數(shù)據(jù)競爭和內(nèi)存重分配Golang slice并發(fā)不安全問題解決
- 并發(fā)安全本地化存儲go-cache讀寫鎖實(shí)現(xiàn)多協(xié)程并發(fā)訪問
- Go指針內(nèi)存與安全性深入理解
- Go語言atomic.Value如何不加鎖保證數(shù)據(jù)線程安全?
- Go?web中cookie值安全securecookie庫使用原理
- Go語言開發(fā)保證并發(fā)安全實(shí)例詳解
- Go語言防范SQL注入CSRF及XSS攻擊實(shí)例探究
相關(guān)文章

golang實(shí)現(xiàn)webgis后端開發(fā)的步驟詳解

Go語言中函數(shù)可變參數(shù)(Variadic Parameter)詳解

一文理解Goland協(xié)程調(diào)度器scheduler的實(shí)現(xiàn)

Golang簡單實(shí)現(xiàn)http的server端和client端