Go語(yǔ)言如何通過(guò)通信共享內(nèi)存
介紹
Go 語(yǔ)言使用 goroutine 和 channel,可以實(shí)現(xiàn)通過(guò)通信共享內(nèi)存。
本文我們介紹 Go 語(yǔ)言怎么通過(guò)通信共享內(nèi)存。
goroutine 和 channel
在了解 Go 語(yǔ)言怎么通過(guò)通信共享內(nèi)存之前。我們需要先了解一些預(yù)備知識(shí),即 goroutine 和 channel 是什么?
goroutine :
goroutine 具有簡(jiǎn)單的模型:它是與其它 goroutine 并發(fā)運(yùn)行在同一地址空間的函數(shù)。
goroutine 是輕量級(jí)的,所有消耗幾乎就只有??臻g的分配。而且棧最開(kāi)始是非常小的,所以他們很廉價(jià),僅在需要時(shí)才會(huì)隨著堆空間的分配(和釋放)而變化。
摘自「Effective Go - channels[1]」。
注意:goroutine 之所以取名為 goroutine,是因?yàn)楝F(xiàn)有的術(shù)語(yǔ) - 線程、協(xié)程、進(jìn)程等等 - 無(wú)法準(zhǔn)確傳達(dá)它的含義。也有些資料將 goroutine 翻譯為 Go 協(xié)程或 Go 程。
使用 goroutine 也非常簡(jiǎn)單,在函數(shù)或方法前添加 go 關(guān)鍵字,即可在新的 goroutine 中調(diào)用它。當(dāng)調(diào)用完成后,該 goroutine 也會(huì)安靜地退出。
此外,匿名函數(shù)也可以在 goroutine 中調(diào)用。
關(guān)于 goroutine 的實(shí)現(xiàn)原理和調(diào)度器模型 GPM,感興趣的讀者朋友們可以自行查閱相關(guān)資料。
channel:
我們已了解,什么是 goroutine,以及怎么使用 goroutine 調(diào)用函數(shù)或方法、匿名函數(shù)。
但是,想要實(shí)現(xiàn) goroutine 之間的通信,我們還需要了解 channel。
channel 需要使用內(nèi)置函數(shù) make 分配內(nèi)存,其結(jié)果值充當(dāng)了對(duì)底層數(shù)據(jù)結(jié)構(gòu)的引用。如果提供了一個(gè)可選的參數(shù),它就會(huì)為該 channel 設(shè)置緩沖區(qū)大小,否則,該 channel 則為無(wú)緩沖區(qū)的 channel。
關(guān)于 channel 的實(shí)現(xiàn)原理,感興趣的讀者朋友們可以閱讀「Golang 語(yǔ)言中的 channel 實(shí)現(xiàn)原理」。
需要注意的是,兩個(gè) goroutine 之間通過(guò)無(wú)緩沖區(qū)的 channel 通信時(shí),同步交換數(shù)據(jù)。
作為兩個(gè) goroutine 之間的通信管道,向 channel 中發(fā)送數(shù)據(jù)的 goroutine 稱為“發(fā)送者”,反之,從 channel 中接收數(shù)據(jù)的 goroutine 稱為“接收者”。
通過(guò)通信共享內(nèi)存
我們已經(jīng)基本了解 Go 語(yǔ)言的 goroutine 和 channel,接下來(lái)我們看一下兩個(gè) goroutine 之間怎么使用 channel (無(wú)緩沖區(qū)和緩沖區(qū))進(jìn)行通信?
無(wú)緩沖區(qū) channel:
示例代碼:
func main() {
c := make(chan int) // 定義一個(gè)無(wú)緩沖區(qū) channel
go func() { // 啟動(dòng)一個(gè) goroutine 調(diào)用匿名函數(shù)
fmt.Println("啟動(dòng)一個(gè) goroutine 調(diào)用匿名函數(shù)")
c <- 1 // 該 goroutine 向 channel 發(fā)送一個(gè)值(信號(hào))
}()
fmt.Println("main 函數(shù)")
out := <-c // main goroutine 從 channel 中接收一個(gè)值(信號(hào)),再未接收到值(信號(hào))之前,一直阻塞
fmt.Println(out) // 該打印無(wú)實(shí)際意義,僅為了讀者容易理解
}
閱讀上面這段代碼,我們定義一個(gè)無(wú)緩沖區(qū) channel,執(zhí)行匿名函數(shù)的 goroutine 作為發(fā)送者,main goroutine 作為接收者。
需要注意的是,無(wú)緩沖區(qū) channel,接收者在收到值之前,發(fā)送者會(huì)一直阻塞。同理,發(fā)送者在發(fā)送值之前,接收者也會(huì)一直阻塞。
緩沖區(qū) channel:
示例代碼:
func main() {
// c := make(chan int) // 無(wú)緩沖區(qū) channel
c := make(chan int, 5) // 緩沖區(qū) channel
for i := 0; i < 20; i++ {
c <- 1
go func() {
fmt.Println("do something:", i)
<-c
}()
}
time.Sleep(time.Second * 2) // 為了防止 main goroutine 提前退出
}
閱讀上面這段代碼,我們定義一個(gè)緩沖區(qū)大小為 5 的 channel,執(zhí)行匿名函數(shù)的 goroutine 作為接收者,main goroutine 作為發(fā)送者。
需要注意的是,該段代碼中有 5 個(gè)執(zhí)行匿名函數(shù)的 goroutine,即 N 個(gè)接收者,1 個(gè)發(fā)送者(main goroutine)。
我們前面講過(guò),接收者在收到值之前會(huì)一直阻塞,而無(wú)緩沖區(qū) channel 在接收者收到值之前,發(fā)送者會(huì)一直阻塞。
如果我們將上面這段代碼中的緩沖區(qū) channel 換成無(wú)緩沖區(qū) channel,N - 1 個(gè)接收者在接收到值之前,發(fā)送者會(huì)一直阻塞,發(fā)送者阻塞,導(dǎo)致接收者一直接收不到值,也會(huì)一直阻塞,從而導(dǎo)致死鎖。
上面這段話有些拗口,讀者朋友們可以通過(guò)運(yùn)行使用無(wú)緩沖區(qū) channel 的代碼來(lái)幫助自己理解。
我們運(yùn)行使用緩沖區(qū)大小為 5 的 channel 的代碼,發(fā)現(xiàn)代碼可以正常運(yùn)行,發(fā)送者和接收者之間不會(huì)產(chǎn)生死鎖。
這是因?yàn)榫彌_區(qū) channel,發(fā)送者僅在值被復(fù)制到緩沖區(qū)之前阻塞,如果緩沖區(qū)已滿,發(fā)送者會(huì)一直阻塞,直到某個(gè)接收者取出一個(gè)值。
回到上面這段示例代碼中,執(zhí)行匿名函數(shù)的 N 個(gè) goroutine 作為接收者,在沒(méi)有收到 main goroutine 發(fā)送的數(shù)據(jù)之前,一直處于阻塞狀態(tài),直到作為發(fā)送者的 main goroutine 發(fā)送數(shù)據(jù)到緩沖區(qū) channel 中。
讀者朋友們?nèi)绻屑?xì)閱讀這段代碼,會(huì)發(fā)現(xiàn)上面這段代碼雖然不會(huì)產(chǎn)生死鎖,但是存在一個(gè) bug。
解決方案可以閱讀我們之前的一篇文章「Go 語(yǔ)言使用 goroutine 運(yùn)行閉包的“坑”」,限于篇幅,我就不在本文中贅述了。
總結(jié)
本文我們介紹 Go 語(yǔ)言中,什么是 goroutine 和 channel,其中 channel 分為無(wú)緩沖區(qū)和緩沖區(qū)。
在簡(jiǎn)單了解 goroutine 和 channel 后,我們又介紹怎么使用 channel,實(shí)現(xiàn)兩個(gè) goroutine 之間通信。
以上就是Go語(yǔ)言如何通過(guò)通信共享內(nèi)存的詳細(xì)內(nèi)容,更多關(guān)于Go語(yǔ)言通信共享內(nèi)存的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
如何使用Golang發(fā)送Get和Post請(qǐng)求
這篇文章主要給大家介紹了關(guān)于如何使用Golang發(fā)送Get和Post請(qǐng)求的相關(guān)資料,Go語(yǔ)言(Golang)的標(biāo)準(zhǔn)庫(kù)提供了處理HTTP請(qǐng)求的功能,這使得將Go用于web應(yīng)用程序變得非常容易,需要的朋友可以參考下2023-06-06
使用Go實(shí)現(xiàn)偽靜態(tài)URL重寫功能
在Web開(kāi)發(fā)中,偽靜態(tài)URL已成為優(yōu)化網(wǎng)站架構(gòu)和提升SEO的常用技術(shù)手段,偽靜態(tài)URL是一種介于動(dòng)態(tài)URL和靜態(tài)URL之間的解決方案,本文給大家介紹了如何使用Go實(shí)現(xiàn)偽靜態(tài)URL重寫功能,需要的朋友可以參考下2024-08-08
Golang中由零值和gob庫(kù)特性引起B(yǎng)UG解析
這篇文章主要為大家介紹了Golang中由零值和gob庫(kù)特性引起B(yǎng)UG解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-04-04
Golang排列組合算法問(wèn)題之全排列實(shí)現(xiàn)方法
這篇文章主要介紹了Golang排列組合算法問(wèn)題之全排列實(shí)現(xiàn)方法,涉及Go語(yǔ)言針對(duì)字符串的遍歷及排列組合相關(guān)操作技巧,需要的朋友可以參考下2017-01-01
golang編程開(kāi)發(fā)使用sort排序示例詳解
這篇文章主要為大家介紹了go語(yǔ)言編程開(kāi)發(fā)使用sort來(lái)排序示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步早日升職加薪2021-11-11

