Golang | 簡介channel常見用法,完成goroutin通信


今天是golang專題的第14篇文章,大家可以點擊上方的專輯回顧之前的內容。

今天我們來看看golang當中另一個很重要的概念——信道。我們之前介紹goroutine的時候曾經提過一個問題,當我們啟動了多個goroutine之后,我們怎么樣讓goroutine之間保持通信呢?

要回答這個問題就需要用到信道。

channel

信道的英文是channel,在golang當中的關鍵字是chan。它的用途是用來在goroutine之間傳輸數據,這里你可能要問了,為什么一定得是goroutine之間傳輸數據呢,函數之間傳遞不行嗎?

因為正常的傳輸數據直接以參數的形式傳遞就可以了,只有在並發場景當中,多個線程彼此隔離的情況下,才需要一個特殊的結構傳輸數據。

Chan看起來比較怪,在其他語言當中基本沒有出現過,但是它的原理和使用都非常簡單。

我們先來看它的使用,首先是定義一個chan,還是老規矩,通過make關鍵字創建。我們之前也提過,golang當中的一個設計原則就是能省則省,能簡單則簡單。從這個make關鍵字就看得出來,它可以創建的東西太多了,既可以創建一個切片,也可以創建map,還可以創建信道。

所以當我們要創建一個chan的時候,可以通過make實現。

Ch := make(chan int)

我們在chan后面跟上一個類型,表示這個信道傳輸的數據類型。如果你想要傳輸任何類型呢,那可以用我們之前說過的interface{}。

Chan創建了之后,我們想要從其中獲取數據或者是把數據放入其中也非常簡單,簡單到都沒有api,直接用形象的傳輸語句就可以了。

比如我們現在有一個chan是ch,我們想要放入數據,我們可以這樣ch <- a。我們想要從ch當中獲取數據,我們可以v := <- ch。

我們用箭頭表示數據的流動,是不是很形象很直觀呢?

阻塞

但是還沒完,chan有一個很關鍵的點在於,chan的使用是阻塞的。也就是說下游從chan當中拿走一個數據我們才可以傳入一個數據。否則的話,傳輸數據的代碼就會一直等待chan清空。

同樣,如果我們定義了一個從chan當中讀取數據的語句,假如當前的chan是空的話,那么它也會一直阻塞等待,直到chan當中有數據了為止。

所以我們就知道了,chan的使用場景當中需要一個生產方,也需要一個消費方。我們來看一個golang官方的一個例子:

package main

import "fmt"

func sum(s []int, c chan int) {
 sum := 0
 for _, v := range s {
  sum += v
 }
 c <- sum // 將和送入 c
}

func main() {
 s := []int{728-940}

 c := make(chan int)
 go sum(s[:len(s)/2], c)
 go sum(s[len(s)/2:], c)
 x, y := <-c, <-c // 從 c 中接收

 fmt.Println(x, y, x+y)
}

我們啟動了兩個goroutine去對數組進行求和並進行返回,goroutine生產的數據是沒辦法直接return的,所以只能通過chan的形式傳輸出來。chan傳輸出來需要下游消費,所以上面兩個goroutine的數據會傳輸到x, y: <-c, <-c 這一句語句當中。

前面說過了,chan的傳輸是阻塞的,所以這一句語句會一直等待,直到上面兩個goroutine都計算完成了為止。

如果你看的有些發蒙,覺得好似有些理解了又好似沒有的話,那么很簡單的一個辦法是在理解的時候把這個使用場景做一個變幻。把chan的使用場景想象成我們之前介紹過的生產者消費者設計模式,chan在其中扮演的角色其實就是隊列。

生產者往隊列當中傳輸數據,消費者進行消費,唯一不同的是這個隊列的容量是1,必須要生產和消費端都准備就緒了才會進行數據傳輸。

chan的緩沖

前文說了,chan的容量只有1,只有消費端和生產端都就緒的時候才可以傳輸數據。我們也可以給chan加上緩沖,如果消費端來不及把所有的數據都消費完,允許生產端先把數據暫時存在chan當中,先不發生阻塞,只有在chan滿了之后才會阻塞。

用法也很簡單,我們在通過make創建chan的時候多加上一個參數表示容量即可,和我們之前創建切片的道理很類似。

Ch := make(chan int100)

比如這樣,我們就創建了一個緩沖區為100的信道。

但多說一句,其實這種情況不太常用,原因也很簡單。因為上下游的消費情況是統一的,如果生產者生產的速度過快,而消費端跟不上的話,即使把它先暫存在緩沖區當中也沒什么用,早晚還是會要阻塞的。

close

當我們對信道使用結束之后,可以通過close語句將它關閉。

Close這個操作只能在生產端進行,消費端如果close信道會引發一個panic。我們在從chan接收數據的時候,可以加上一個參數判斷信道是否關閉。

v, ok := <- ch
if !ok {
 return
}

這樣我們就可以判斷chan關閉的時間了。

今天的文章到這里就結束了,如果喜歡本文的話,請來一波素質三連,給我一點支持吧(關注、轉發、點贊)。

相關閱讀

Python | 面試的常客,經典的生產消費者模式

原文鏈接,求個關注

- END -


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM