您好,登錄后才能下訂單哦!
Go 語言中如何理解協(xié)程通信實現(xiàn)的消息傳遞篇,針對這個問題,這篇文章詳細(xì)介紹了相對應(yīng)的分析和解答,希望可以幫助更多想解決這個問題的小伙伴找到更簡單易行的方法。
通過共享內(nèi)存實現(xiàn)協(xié)程通信,這種方式太過繁瑣,且維護(hù)成本高,Go 語言推薦使用消息傳遞實現(xiàn)并發(fā)通信,這種消息通信機(jī)制被稱為 channel
,中文譯作「通道」,可理解為傳遞消息的通道。
通道是 Go 語言在語言級別提供的協(xié)程通信方式,它是一種數(shù)據(jù)類型,本身是并發(fā)安全的,我們可以使用它在多個 goroutine 之間傳遞消息,而不必?fù)?dān)心通道中的數(shù)據(jù)被污染。
注:需要注意的是,通道是進(jìn)程內(nèi)的通信方式,因此通過通道傳遞對象的過程和調(diào)用函數(shù)時的參數(shù)傳遞行為比較一致,也可以傳遞指針。如果需要跨進(jìn)程通信,建議通過分布式系統(tǒng)的方法來解決,比如使用 Socket 或者 HTTP 等通信協(xié)議,Go 語言對于網(wǎng)絡(luò)方面也有非常完善的支持,學(xué)院君會在介紹完并發(fā)編程后介紹網(wǎng)絡(luò)通信。
前面我們說到通道是一種數(shù)據(jù)類型,和數(shù)組類型類似,一個通道只能傳遞一種類型的值,這個類型需要在聲明通道時指定。在使用通道時,需要通過 make
進(jìn)行聲明,通道對應(yīng)的類型關(guān)鍵字是 chann
:
ch := make(chan int)
這里我們初始化了一個通道類型 ch
,其中只能傳遞 int
類型的值。
我們可以把通道看作是一個先進(jìn)先出(FIFO)的隊列,通道中的元素會嚴(yán)格按照發(fā)送順序排列,繼而按照排列順序被接收,通道元素的發(fā)送和接收都可以通過 <-
操作符來實現(xiàn),發(fā)送時元素值在右,通道變量在左:
ch <- 1 // 表示把元素 1 發(fā)送到通道 ch
接收時通道變量在右,可以通過指定變量接收元素值:
element := <-ch
也可以留空表示忽略:
<-ch
這樣一來,通過箭頭指向我們就可以清楚的判斷是寫入數(shù)據(jù)到通道還是從通道讀取數(shù)據(jù),非常簡單形象。
在系統(tǒng)介紹通道類型的完整語法前,我們先看通過通道類型重寫上篇教程通過共享內(nèi)存實現(xiàn)協(xié)程通信的代碼,創(chuàng)建一個 channel.go
文件,編寫代碼如下:
package main
import (
"fmt"
"time"
)
func add(a, b int, ch chan int) {
c := a + b
fmt.Printf("%d + %d = %d\n", a, b, c)
ch <- 1
}
func main() {
start := time.Now()
chs := make([]chan int, 10)
for i := 0; i < 10; i++ {
chs[i] = make(chan int)
go add(1, i, chs[i])
}
for _, ch := range chs {
<- ch
}
end := time.Now()
consume := end.Sub(start).Seconds()
fmt.Println("程序執(zhí)行耗時(s):", consume)
}
在這個例子中,我們首先定義了一個包含 10 個通道類型的數(shù)組 chs
,并把數(shù)組中的每個通道分配給 10 個不同的協(xié)程。在每個協(xié)程的 add()
函數(shù)業(yè)務(wù)邏輯完成后,我們通過 ch <- 1
語句向?qū)?yīng)的通道中發(fā)送一個數(shù)據(jù)。在所有的協(xié)程啟動完成后,我們再通過 <-ch
語句從通道數(shù)組 chs
中依次接收數(shù)據(jù)(不對結(jié)果做任何處理,相當(dāng)于寫入通道的數(shù)據(jù)只是個標(biāo)識而已,表示這個通道所屬的協(xié)程邏輯執(zhí)行完畢),直到所有通道數(shù)據(jù)接收完畢,然后打印主程序耗時并退出。
之所以上述這段代碼可以實現(xiàn)和「共享內(nèi)存+鎖」一樣的效果,是因為往通道寫入數(shù)據(jù)和從通道接收數(shù)據(jù)都是原子操作,或者說是同步阻塞的,當(dāng)我們向某個通道寫入數(shù)據(jù)時,就相當(dāng)于該通道被加鎖,直到寫入操作完成才能執(zhí)行從該通道讀取數(shù)據(jù)的操作,反過來,當(dāng)我們從某個通道讀取數(shù)據(jù)時,其他協(xié)程也不能操作該通道,直到讀取完成,如果通道中沒有數(shù)據(jù),則會阻塞在這里,直到通道被寫入數(shù)據(jù)。因此,可以看到通道的發(fā)送和接收操作是互斥的,同一時間同一個進(jìn)程內(nèi)的所有協(xié)程對某個通道只能執(zhí)行發(fā)送或接收操作,兩者不可能同時進(jìn)行,這樣就保證了并發(fā)的安全性,數(shù)據(jù)不可能被污染。
綜上可知,上述示例代碼 main()
函數(shù)中的第二個循環(huán)會等到所有子協(xié)程執(zhí)行完畢后才能完成所有通道的接收操作。我們可以執(zhí)行下這段代碼,輸出結(jié)果如下:
程序耗時和共享內(nèi)存相當(dāng),但是代碼要簡潔的多,優(yōu)雅的多。當(dāng)然,本篇教程只是介紹了通道的最基本使用,接下來,我將花幾個教程的篇幅為大家系統(tǒng)介紹通道,并結(jié)合協(xié)程(goroutine)+通道(channel)為大家展現(xiàn) Go 并發(fā)編程的魅力。
關(guān)于Go 語言中如何理解協(xié)程通信實現(xiàn)的消息傳遞篇問題的解答就分享到這里了,希望以上內(nèi)容可以對大家有一定的幫助,如果你還有很多疑惑沒有解開,可以關(guān)注億速云行業(yè)資訊頻道了解更多相關(guān)知識。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。