新聞中心
本文轉(zhuǎn)載自微信公眾號(hào)「吳親強(qiáng)的深夜食堂」,作者吳親庫(kù)里。轉(zhuǎn)載本文請(qǐng)聯(lián)系吳親強(qiáng)的深夜食堂公眾號(hào)。

躺的太久,該起床了。
寧可我卷死別人,不能讓別人卷我。
之前斷斷續(xù)續(xù)看過(guò)Go幾個(gè)模塊的源碼,可從未下筆,導(dǎo)致有些細(xì)節(jié)記不起來(lái)了。打算寫(xiě)一系列文章重新記錄。
channel源碼解析的文章太多了。一篇文章的長(zhǎng)篇大論大部分人沒(méi)耐心看完,所以我打算分開(kāi)寫(xiě),最后附上完整的ppt。
當(dāng)然這其中不會(huì)涉及過(guò)多細(xì)節(jié)源碼,因?yàn)橛袝r(shí)候,細(xì)節(jié)是魔鬼。
介紹
channel一些基礎(chǔ)介紹這里就不過(guò)多涉及了,都1202年了,我不相信用過(guò)Go的人沒(méi)用過(guò)channel。
當(dāng)然下圖也涵蓋了大部分使用姿勢(shì)。
有一道使用channel進(jìn)行任務(wù)編排的經(jīng)典的題。題目如下:
有四個(gè)goroutine,編號(hào)為 1、2、3、4。每秒鐘會(huì)有一個(gè) goroutine打印自己的編號(hào)。請(qǐng)你實(shí)現(xiàn)這個(gè)程序,讓輸出的編號(hào)總是按照 1、2、3、4、1、2、3、4、……的順序打印出來(lái)。就像這樣,
可以自己先思考下,代碼也可以通過(guò)后臺(tái)回復(fù)擊鼓傳花獲取。
原理解析
從一個(gè)簡(jiǎn)單的例子說(shuō)起。
創(chuàng)建一個(gè)main.go文件,代碼如下,
我們來(lái)看看這段代碼編譯以后長(zhǎng)啥樣。
想得到go程序的匯編代碼并不難。
可以使用go tool compile -N -l -S main.go生成匯編代碼:
或者使用go tool compile -N -l main.go先編譯出代碼,然后再使用go tool objdump main.o反匯編出代碼。
還可以通過(guò)go build -gcflags -S main.go同樣可以得到匯編的代碼。
上面兩種我就不演示了,可以自行實(shí)驗(yàn)。他們之中flag的具體含義也可以自行了解。
如果你覺(jué)得上面要自己敲代碼比較麻煩,我推薦一個(gè)更加直接可視化的工具。
綜上,從編譯的代碼我們可以看出,上述初始化一個(gè)channel,實(shí)際上調(diào)用的是runtime.makechan。
- ch := make(chan struct{})
圖片從函數(shù)中,我們能知道最終返回一個(gè)runtime.hchan的指針。
runtime.hchan結(jié)構(gòu)。
我們先來(lái)解釋hchan結(jié)構(gòu)體各個(gè)字段的含義,之后在案例介紹中會(huì)更加詳細(xì)的說(shuō)明他們的作用。
先來(lái)看qcount和dataqsiz有什么區(qū)別?
你去銀行辦事,銀行有5個(gè)辦事窗口,那么dataqsiz就等于5。在這里體現(xiàn)的是channel的容量為5。去銀行的時(shí)候,當(dāng)前有3個(gè)窗口有人正在辦事,那么qcount就等于3,體現(xiàn)channel當(dāng)前有3個(gè)數(shù)據(jù)元素。那么此時(shí)銀行還可以再接待2個(gè)客戶,對(duì)應(yīng)還可以往channel發(fā)送2個(gè)數(shù)據(jù)元素。
其他字段現(xiàn)在看看說(shuō)明就行了,后面會(huì)細(xì)講。
到這里我們就知道創(chuàng)建一個(gè)channel本質(zhì)上就是得到一個(gè)runtime.hchan的指針,后續(xù)對(duì)此chan的操作,無(wú)非就是對(duì)結(jié)構(gòu)體字段進(jìn)行相對(duì)應(yīng)的操作。
同時(shí)我們也能猜出,為啥channel能在不同的g中傳遞消息,而對(duì)于使用者來(lái)說(shuō)不用擔(dān)心并發(fā)的問(wèn)題。
其實(shí)就是hchan內(nèi)部使用互斥鎖來(lái)保證了并發(fā)安全。
最后我們來(lái)看一下runtime.makechan函數(shù)核心實(shí)現(xiàn),當(dāng)然注釋已經(jīng)很明白了。
可以看到創(chuàng)建的時(shí)候有一段switch分支代碼,那么什么情況下會(huì)走對(duì)應(yīng)的case呢?
根據(jù)上面的信息,我們可以得出,
- 如果創(chuàng)建一個(gè)無(wú)緩沖channel ,那么只需要為runtime.hchan本身分配一段內(nèi)存空間即可。
- 如果創(chuàng)建的緩沖channel存儲(chǔ)的類型不是指針類型,會(huì)為當(dāng)前channel和存儲(chǔ)類型元素的緩沖區(qū),分配一塊連續(xù)的內(nèi)存空間。
- 在默認(rèn)情況下(緩沖channel存儲(chǔ)類型包含指針),會(huì)單獨(dú)為runtime.hchan和緩沖區(qū)分配內(nèi)存。
總結(jié)
這篇我們主要介紹了如何獲取go程序的匯編代碼,通過(guò)匯編代碼知道創(chuàng)建channel的具體函數(shù)runtime.makechan。
同時(shí)我們還知道不同的創(chuàng)建姿勢(shì)會(huì)導(dǎo)致走向不同的內(nèi)存空間分配邏輯。
最后通過(guò)創(chuàng)建函數(shù)我們知道channel在程序運(yùn)行時(shí)是使用runtime.hchan來(lái)表示。
下一篇我們繼續(xù)。
分享文章:徹底搞懂Channel原理之一
本文網(wǎng)址:http://www.fisionsoft.com.cn/article/coeiojg.html


咨詢
建站咨詢
