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