Go的并發(fā)沒(méi)有它,就像iphone沒(méi)有網(wǎng)絡(luò)一樣
回復(fù)“Go語(yǔ)言”即可獲贈(zèng)從入門(mén)到進(jìn)階共10本電子書(shū)
Go的并發(fā)沒(méi)有它,就像iphone沒(méi)有網(wǎng)絡(luò)一樣

“ 閱讀本文大概需要4.6分鐘 ”
簡(jiǎn)介
? ? Golang的并發(fā)屬性是該語(yǔ)言的一個(gè)大殺器,說(shuō)到并發(fā)就不能不提Channel,你可以把它看成一個(gè)管道,通過(guò)它并發(fā)核心單元就可以發(fā)送或者接收數(shù)據(jù)進(jìn)行通訊。這篇文章來(lái)深入了解一下 channel。
channel 的設(shè)計(jì)是基于 CSP 模型的。CSP 是 Communicating Sequential Process 的簡(jiǎn)稱(chēng),中文可以叫做通信順序進(jìn)程,是一種并發(fā)編程模型,由 Tony Hoare 于 1977 年提出。簡(jiǎn)單來(lái)說(shuō),CSP 模型由并發(fā)執(zhí)行的實(shí)體(線程或者進(jìn)程)所組成,實(shí)體之間通過(guò)發(fā)送消息進(jìn)行通信,這里發(fā)送消息時(shí)使用的就是通道,或者叫 channel。CSP 模型的關(guān)鍵是關(guān)注 channel,而不關(guān)注發(fā)送消息的實(shí)體。Go 語(yǔ)言實(shí)現(xiàn)了 CSP 部分理論,goroutine 對(duì)應(yīng) CSP 中并發(fā)執(zhí)行的實(shí)體,channel 也就對(duì)應(yīng)著 CSP 中的 channel。
創(chuàng)建Channel
Go中的Channel使用
chan作為關(guān)鍵字。無(wú)緩沖chan情況下,發(fā)送和接收會(huì)一直阻塞著,直到另一方準(zhǔn)備好。這種方式可以用來(lái)在gororutine中進(jìn)行同步,- 而需要使用鎖或者條件變量。
有緩沖chan,可以盡量避免阻塞,提高應(yīng)用的性能,典型的以時(shí)間換空間。
aChan := make(chan int) ?// 創(chuàng)建無(wú)緩沖chan
bChan := make(chan int, N) // 創(chuàng)建緩沖為N的chan賦值和取值
? ? 從以下代碼中看不出它的巨大作用,很正常,那是因?yàn)樗麄儍蓷l語(yǔ)句通常不在一起,例如:協(xié)程A發(fā)送數(shù)據(jù),協(xié)程B接收數(shù)據(jù)。
mchan <- value ?// 發(fā)送值v到Channel ch中
value := <-mchan // 從Channel ch中接收數(shù)據(jù),并將數(shù)據(jù)賦值給vSelect
? ? Selsect是獲取Channel中數(shù)據(jù)的最常用方式。
select 一定程度上可以類(lèi)比于 linux 中的 IO 多路復(fù)用中的 select。后者相當(dāng)于提供了對(duì)多個(gè) IO 事件的統(tǒng)一管理,而 Golang 中的 select 相當(dāng)于提供了對(duì)多個(gè) channel 的統(tǒng)一管理。當(dāng)然這只是 select 在 channel 上的一種使用方法。
func main(){
? ?ch1 := make(chan int, 1)
? ?ch2 := make(chan int, 1)
? ?select {
? ? ? ?case e1 := <-ch1:
? ? ? ?//如果ch1通道成功讀取數(shù)據(jù),則執(zhí)行該case處理語(yǔ)句
? ? ? ? ? ?fmt.Printf("1th case is selected. e1=%v",e1)
? ? ? ?case e2 := <-ch2:
? ? ? ?//如果ch2通道成功讀取數(shù)據(jù),則執(zhí)行該case處理語(yǔ)句
? ? ? ? ? ?fmt.Printf("2th case is selected. e2=%v",e2)
? ? ? ?default:
? ? ? ?//如果上面case都沒(méi)有成功,則進(jìn)入default處理流程
? ? ? ? ? ?fmt.Println("default!.")
? ?}
}for…range
? ? for …… range語(yǔ)句可以處理Channel。
? ?go func() {
? ? ? ?time.Sleep(1 * time.Hour)
? ?}()
? ?c := make(chan int)
? ?go func() {
? ? ? ?for i := 0; i < 10; i = i + 1 {
? ? ? ? ? ?c <- i
? ? ? ?}
? ? ? ?close(c)
? ?}()
? ?for i := range c {
? ? ? ?fmt.Println(i)
? ?}
? ?fmt.Println("Finished")timeout
? ? Select很重要的一個(gè)應(yīng)用就是超時(shí)處理。因?yàn)樯厦嫣峁┑膁emo,select語(yǔ)句就會(huì)一直阻塞著。這時(shí)候我們可能就需要一個(gè)超時(shí)操作,用來(lái)處理超時(shí)的情況。下面這個(gè)例子我們會(huì)在2秒后往channel c1中發(fā)送一個(gè)數(shù)據(jù),但是Select設(shè)置為1秒超時(shí),因此我們會(huì)打印出timeout 1,而不是result 1。
? ?c1 := make(chan string, 1)
? ?go func() {
? ? ? ?time.Sleep(time.Second * 2)
? ? ? ?c1 <- "result 1"
? ?}()
? ?select {
? ?case res := <-c1:
? ? ? ?fmt.Println(res)
? ?case <-time.After(time.Second * 1):
? ? ? ?fmt.Println("timeout 1")
? ?}close
? ? Go內(nèi)建的close方法就可以用來(lái)關(guān)閉channel。但如果channel 已經(jīng)被關(guān)閉,繼續(xù)往它發(fā)送數(shù)據(jù)會(huì)導(dǎo)致panic: send on closed channel:
?close(mChan)
-------------------?End?-------------------
往期精彩文章推薦:

歡迎大家點(diǎn)贊,留言,轉(zhuǎn)發(fā),轉(zhuǎn)載,感謝大家的相伴與支持
想加入Go學(xué)習(xí)群請(qǐng)?jiān)诤笈_(tái)回復(fù)【入群】
萬(wàn)水千山總是情,點(diǎn)個(gè)【在看】行不行
