GO通道chan__go

來源:互聯網
上載者:User

chan用於goroutine間的通訊 1、基礎 有緩衝通道和無緩衝通道

無緩衝通道:make(chan int)
有緩衝通道:make(chan int, 5) 無緩衝通道會導致發送和接收的goroutine同步化

主要體現在如下兩點:
- 無緩衝通道會使發送goroutine阻塞,直到對應的chan上有接收者

package mainimport (    "fmt"    "time")var ch chan intfunc main(){    var i int = 9    ch = make(chan int)    go waiting()    fmt.Println("向chan發送,時間:",time.Now())    ch <- i    fmt.Println("發送完畢,時間:", time.Now())    //ch <- i    time.Sleep(10000000000)}func waiting(){    for {        time.Sleep(10000000000)//接收協程等待10秒        i, ok := <-ch        if !ok {            fmt.Println("chan is close!")            break        }        fmt.Println("recv:", i)    }    fmt.Println("waiting end!")}

輸出:

winterdeMacBook-Pro:chantest winter$ ./chantest1向chan發送,時間: 2017-12-07 16:12:04.856740287 +0800 CSTrecv: 9發送完畢,時間: 2017-12-07 16:12:14.857350085 +0800 CSTwinterdeMacBook-Pro:chantest winter$
同樣,無緩衝通道會使接收goroutine阻塞,直到對應的chan上有發送
package mainimport (    "fmt"    "time")var ch chan intfunc main(){    var i int = 9    ch = make(chan int)    go waiting()    fmt.Println("向chan發送,時間:",time.Now())    time.Sleep(10000000000)//等待10秒後向chan發送資料    ch <- i    fmt.Println("發送完畢,時間:", time.Now())    //ch <- i    time.Sleep(10000000000)}func waiting(){    for {        //time.Sleep(10000000000)//接收協程等待10秒        fmt.Println("開始接收chan中的資料,時間:", time.Now())        i, ok := <-ch        fmt.Println("chan中有資料,時間:",time.Now())        if !ok {            fmt.Println("chan is close!")            break        }        fmt.Println("recv:", i)    }    fmt.Println("waiting end!")}

輸出:

winterdeMacBook-Pro:chantest winter$ ./chantest1向chan發送,時間: 2017-12-07 16:17:35.598050582 +0800 CST開始接收chan中的資料,時間: 2017-12-07 16:17:35.598060998 +0800 CST發送完畢,時間: 2017-12-07 16:17:45.602548482 +0800 CSTchan中有資料,時間: 2017-12-07 16:17:45.602599793 +0800 CSTrecv: 9開始接收chan中的資料,時間: 2017-12-07 16:17:45.602665344 +0800 CST
緩衝通道,相當與一個隊列,隊列的最大長度在建立時指定 一個空的chan,會導致接收goroutine阻塞 一個滿的chan,會導致發送goroutine阻塞 2、會導致程式掛掉的異常 nil通道的發送和接收 chan的零值是nil,沒有初始化的等於nil
package mainimport (    "fmt")func main(){    var ch chan int    if ch == nil {        fmt.Println("ch is nil")    }}

輸出:

winterdeMacBook-Pro:chantest winter$ ./chantest1ch is nil
nil值的chan上的發送和接收會導致程式掛掉並提示“nil chan”
package mainimport (    "fmt")var ch chan intfunc main(){    var i int = 9    go waiting()    ch <- i}func waiting(){    i:= <-ch    fmt.Println("recv:", i)}

輸出:

winterdeMacBook-Pro:chantest winter$ ./chantest1fatal error: all goroutines are asleep - deadlock!goroutine 1 [chan send (nil chan)]:main.main()        /Users/winter/code/go_project/src/test/chantest/chantest1.go:10 +0x64goroutine 5 [chan receive (nil chan)]:main.waiting()        /Users/winter/code/go_project/src/test/chantest/chantest1.go:15 +0x50created by main.main        /Users/winter/code/go_project/src/test/chantest/chantest1.go:9 +0x35
向沒有接收者的通道發送

向沒有接受者的通道發送資料,程式會掛掉,會提示“deadlock”

package mainimport (    "fmt")var ch chan intfunc main(){    var i int = 9    ch = make(chan int)    //ch沒有接收者    ch <- i}func waiting(){    i:= <-ch    fmt.Println("recv:", i)}

輸出:

winterdeMacBook-Pro:chantest winter$ ./chantest1fatal error: all goroutines are asleep - deadlock!goroutine 1 [chan send]:main.main()        /Users/winter/code/go_project/src/test/chantest/chantest1.go:11 +0x7f
chan後的關閉(close)操作 在一個關閉後的chan上進行接收操作,將擷取所有已經發送的值,直到chan為空白,然後阻塞解除,會一直擷取到chan元素類型對應的零值。即從一個關閉的chan上讀取資料,永遠不會阻塞在接收端可以判斷chan是否關閉,但是沒有辦法在發送端判斷chan是否關閉,所以只能在發送端關閉chan關閉chan是非必需的,因為GC回收chan,不是根據chan是否關閉,而是根據是否可以訪問來決定的 一般情況下,不要關閉chan,因為關閉一個chan存在以下風險:

關閉一個已經關閉的chan會導致程式崩潰
關閉一個零值chan會導致程式崩潰
chan關閉後,發送操作會導致程式崩潰

package mainimport (    "fmt"    "time")var ch chan intfunc main(){    var i int = 9    ch = make(chan int)    go waiting()    ch <- i    close(ch)    ch <- i    time.Sleep(10000000000)}func waiting(){    for {        i:= <-ch        fmt.Println("recv:", i)    }}

輸出:

winterdeMacBook-Pro:chantest winter$ ./chantest1recv: 9recv: 0recv: 0recv: 0recv: 0recv: 0recv: 0panic: send on closed channelgoroutine 1 [running]:main.main()        /Users/winter/code/go_project/src/test/chantest/chantest1.go:14 +0xda

可見,接收的goroutine收到最後一個元素後,一直擷取到int的零值。直到主goroutine往關閉的chan發送導致程式掛掉。
那麼如何判斷一個chan是否已經被close?從chan讀取資料,一般都簡寫成 i := <- ch,其實返回兩個值,例如i, ok := <-ch,第一個傳回值表示擷取的元素,第二個傳回值是bool型,等於false表示讀取異常。所以可以根據這個傳回值判斷chan是否被close。

package mainimport (    "fmt"    "time")var ch chan intfunc main(){    var i int = 9    ch = make(chan int)    go waiting()    ch <- i    close(ch)    //ch <- i    time.Sleep(10000000000)}func waiting(){    for {        i, ok := <-ch        if !ok {            fmt.Println("chan is close!")            break        }        fmt.Println("recv:", i)    }    fmt.Println("waiting end!")}
相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.