golang的Channel

來源:互聯網
上載者:User
這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。

golang的Channel

Channel 是 golang 一個非常重要的概念,如果你是剛開始使用 golang 的開發人員,你可能還沒有真正接觸這一概念,本篇我們將分析 golang 的Channel

1. 引入

要講 Channel 就避不開 Goroutine -- 協程。閑話不說, 直接上個例子

Goroutine demo

package mainimport (    "fmt"    "time")func main() {    origin := 1    go doSomeCompute(origin)    time.Sleep(5 * time.Second)}func doSomeCompute(num int) {    result := num * 2    fmt.Println(result)    return}

簡單來說,例子中有一個 main 的協程,一個 doSomeCompute 的協程。還有個延時退出的方法等待計算協程計算結果。我們嘗試思考這個例子的一些問題:

a. 如何擷取 doSomeCompute 的計算結果?

b. 如何擷取 doSomeCompute 的執行狀態,當前是執行完了還是執行中?

如何解決這種問題呢?

Channel!

2. Channel

Channel怎麼處理上面的問題?我們直接上代碼:

舉例

package mainimport (    "fmt")func main() {    origin := 1    //一個無緩衝Channel    res := make(chan int)    go doSomeCompute(origin, res)    fmt.Println(<-res)}func doSomeCompute(num int, res chan int) {    result := num * 2    res <- result}

例子中,Channel 充當起了協程間通訊的橋樑。Channel 可以傳遞到協程說明它是安全執行緒的,事實也是如此。Channel 可以理解為管道,協程 doSomeCompute 向 Channel 寫入結果, main 中讀取結果。注意,例子中讀取 Channel 的地方會阻塞直到拿到計算結果,這樣就解決了問題 a 和 b。

2. Channel 的方向性

上面的例子中,計算協程是負責計算並將計算結果寫入 Channel ,如果我們希望保證計算協程不會從 Channel 中讀取資料該怎麼處理?很簡單,看例子:

func doSomeCompute(num int, res chan<- int) {    result := num * 2    res <- result}

這個參數的聲明 chan<- int 就表示該函數只能講資料寫入 Channel ,而不能從中讀取資料。後面的 int 表示 Channel 中資料的格式。同樣的, 只可以讀取資料的 Channel 可以聲明為 <-chan int 。而例子中不帶有方向聲明的 Channel 則既可以寫入也可以讀取。

3. 阻塞性質

Channel 的讀取和寫入操作在各自的協程內部都是阻塞的。比如例子中 fmt.Println(<-res) , 這一語句會阻塞直至計算協程將計算結果放入,可以讀出。也就是說,協程會阻塞直至從 res 中讀出資料。

注意,無緩衝的 Channel 的讀寫都是阻塞的,有緩衝的 Channel 可以一直向裡面寫資料,直到緩衝滿才會阻塞。讀取資料同理, 直至 Channel 為空白才阻塞。

用一個典型的例子來說明緩衝和非緩衝 Channel 的區別:

package mainimport "fmt"func doSomeCompute(ch chan int) {    fmt.Println("deadlock test")    <- ch}func main() {    ch := make(chan int)    ch <- 1    go doSomeCompute(ch)}

例子中,main 協程會向 ch 寫入資料, 這一過程是阻塞的,也就是說,doSomeCompute 協程無法執行,程式死結。輸出如下:

fatal error: all goroutines are asleep - deadlock!goroutine 1 [chan send]:main.main()    C:/mygo/src/demo/blog.go:12 +0x73exit status 2

如果改成有緩衝的 Channel :

package mainimport (    "fmt"    "time")func doSomeCompute(ch chan int) {    fmt.Println("deadlock test")    <- ch}func main() {    ch := make(chan int, 1)    ch <- 1    go doSomeCompute(ch)    time.Sleep(1 * time.Second)}

有與有緩衝的 Channel 寫入後不阻塞(下一次寫入才會阻塞),程式會繼續執行。

4. Channel 的資料結構

Channel 在 golang 中實際上就是個資料結構。在 Golang 源碼中, Channel 的資料結構 Hchan 的定義如下:

struct  Hchan{    uint32  qcount;         // total data in the q    uint32  dataqsiz;       // size of the circular q    uint16  elemsize;    bool    closed;    uint8   elemalign;    Alg*    elemalg;        // interface for element type    uint32  sendx;          // send index    uint32  recvx;          // receive index    WaitQ   recvq;          // list of recv waiters    WaitQ   sendq;          // list of send waiters    Lock;};

時間倉促,這次對 Channel 介紹寫的有點簡單粗暴,下次再寫。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.