Go channel類型

Channel是Go中的一個核心類型,可以把它看成一個管道,Goroutine通過它可以發(fā)送或者接收數(shù)據(jù)并進行通訊屑柔。它的操作符號是 <- ,就像map和slice一樣,channel必須先創(chuàng)建才能夠使用:

ch=make(chan int) // int表示chan里面的數(shù)據(jù)類型
ch :=make(chan interface{}) //任意數(shù)據(jù)類型的chan

Channel類型

Channel類型的定義格式如下:

ChannelType = ( "chan" | "chan" "<-" | "<-" "chan" ) ElementType .

包括三種類型的定義漫仆。 <- 表示數(shù)據(jù)的流向,如果沒有指定 <-坤按,則表示chan既可以發(fā)送數(shù)據(jù)也可以接受數(shù)據(jù)毯欣。

Channel聲明

chan int //既可以發(fā)送數(shù)據(jù)也可以接受數(shù)據(jù)
<- chan int  //只允許從chan接受int類型數(shù)據(jù)
chan <- int //只允許發(fā)送int類型數(shù)據(jù)到chan

Channel設(shè)置容量

make(chan int ,100)

//  Channel: The channel's buffer is initialized with the specified
//  buffer capacity. If zero, or the size is omitted, the channel is
//  unbuffered.
func make(t Type, size ...IntegerType) Type

參數(shù)100用來設(shè)置channel的緩存容量,也是channel最大可以容納的元素數(shù)量臭脓。
元素數(shù)量超過緩存大小酗钞,向channel發(fā)送數(shù)據(jù)會阻塞。
元素數(shù)量為空来累,從channel接受數(shù)據(jù)會阻塞砚作。
如果緩存大小設(shè)置為0,發(fā)送和接受都將被阻塞嘹锁。

Channel類型安全
多個goroutine向channel發(fā)送或者接受數(shù)據(jù)葫录,是線程安全的,不要采取額外的同步措施领猾。

Channel數(shù)據(jù)順序
chnnel是一個FIFO(先進先出)隊列米同,向channel發(fā)送數(shù)據(jù)的順序和從channel接受數(shù)據(jù)的順序一致。

Channel closed
channel關(guān)閉之后摔竿,繼續(xù)向channel發(fā)送數(shù)據(jù)會panic,從channel接受數(shù)據(jù)不會panic面粮,會立即返回,返回的是chan數(shù)據(jù)類型的零值继低。

       ch :=make(chan int,10)
    close(ch)
    a :=<- ch
    println(a) //print 0
    //ch <- 1 //panic: send on closed channel

我們也可以通過以下代碼來檢查channel是否關(guān)閉

  ch :=make(chan int,10)
  close(ch)
  a,ok :=<-ch //ok==false熬苍,表示channel被關(guān)閉

利用這個特性我們可以用來為中間的任務(wù)執(zhí)行步驟的設(shè)置超時時間,超過指定時間任務(wù)沒有執(zhí)行完成袁翁,關(guān)閉channel柴底,主邏輯就繼續(xù)向下執(zhí)行。

Channel 遍歷

通過range可以遍歷輸出channel中的元素粱胜,channle 被close之后依然會輸出channel中的元素似枕。以下代碼是向緩沖區(qū)為10的元素發(fā)送數(shù)據(jù),然后關(guān)閉channle之后依然可以遍歷輸出channel里面的元素:

func main() {
    c := make(chan int,10)
    for i := 0; i < 10; i = i + 1 {
        c <- i
    }
    close(c)

    for i := range c {
        fmt.Print(i)
    }
}
 //輸出:0123456789

下面代碼是向一個沒有緩沖區(qū)的channel發(fā)送數(shù)據(jù)年柠,通過range遍歷從channel接受數(shù)據(jù)打印:

func main() {

    c := make(chan int)
    go func() {
        for i := 0; i < 10; i = i + 1 {
            c <- i
        }
        close(c) //必須close,否則遍歷channel后會panic褪迟。會提示:fatal error: all goroutines are asleep - deadlock!
    }()

    for i := range c {
        fmt.Println(i)
    }
    fmt.Println("Finished")
}

Channel用于select語句
select語句選擇一組send或者receive操作去處理冗恨。它的case可以是send語句,也可以是receive語句味赃,亦或default掀抹。如果case有多個channel可以接受數(shù)據(jù),那么Go會隨機選擇一個case去處理心俗,如果沒有任何一個case要處理傲武,有default的情況下會執(zhí)行default邏輯蓉驹,如果沒有default項,則會一直阻塞揪利,直到滿足某個case條件态兴。

下面代碼是打印斐波那契數(shù)列每一項,通過在select語句之外嵌套for循環(huán)可以一直處理,直到遇到退出語句疟位。

package main

import "fmt"

func fibonacci(c, quit chan int) {
    x, y := 0, 1
    for {
        select {
        case c <- x:
            x, y = y, x+y
        case <-quit:
            fmt.Println("quit")
            return
        }
    }
}
func main() {
    c := make(chan int)
    quit := make(chan int)
    go func() {
        for i := 0; i < 10; i++ {
            fmt.Println(<-c)
        }
        quit <- 0
    }()
    fibonacci(c, quit)
}


打印結(jié)果

0
1
1
2
3
5
8
13
21
34
quit

Channel用于timeout
select case使用channel會一直阻塞知道滿足某個case條件才會退出瞻润。不過我們可以通過time.After(timeout) 設(shè)置超時時間,超時時間到后就會自動退出甜刻。

下面代碼中channel c1休眠2秒后會寫入數(shù)據(jù)绍撞,然后case滿足,打印result 1得院。
不過打印的是timeout 1傻铣,因為第二個case語句設(shè)置了超時時間。

package main

import "time"
import "fmt"
func main() {
    c1 := make(chan string, 1)
    go func() {
        time.Sleep(time.Second * 2)
        c1 <- "result 1"
    }()
    
    select {
    case res := <-c1:
        fmt.Println(res)
    case <-time.After(time.Second * 1):
        fmt.Println("timeout 1")
    }
}

打印結(jié)果

timeout 1

Channle groutine同步

利用channel我們可以實現(xiàn)groutine之間相互通信祥绞。
下面的例子是啟動一個groutine區(qū)完成任務(wù)非洲,任務(wù)完成后想channel寫入數(shù)據(jù)。
main方法收到寫入數(shù)據(jù)信號就打印done,表示任務(wù)完成就谜,否則一直阻塞知道groutine完成任務(wù)怪蔑。

package main

import (
    "time"
)
func worker(done chan bool) {
    time.Sleep(time.Second)
    // 通知任務(wù)已完成
    done <- true
}
func main() {
    done := make(chan bool, 1)
    go worker(done)
    // 等待任務(wù)完成
    <-done
    println("done")
}

參考文章:https://colobu.com/2016/04/14/Golang-Channels/

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市丧荐,隨后出現(xiàn)的幾起案子缆瓣,更是在濱河造成了極大的恐慌,老刑警劉巖虹统,帶你破解...
    沈念sama閱讀 211,376評論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件弓坞,死亡現(xiàn)場離奇詭異,居然都是意外死亡车荔,警方通過查閱死者的電腦和手機渡冻,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,126評論 2 385
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來忧便,“玉大人族吻,你說我怎么就攤上這事≈樵觯” “怎么了超歌?”我有些...
    開封第一講書人閱讀 156,966評論 0 347
  • 文/不壞的土叔 我叫張陵,是天一觀的道長蒂教。 經(jīng)常有香客問我巍举,道長,這世上最難降的妖魔是什么凝垛? 我笑而不...
    開封第一講書人閱讀 56,432評論 1 283
  • 正文 為了忘掉前任懊悯,我火速辦了婚禮蜓谋,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘炭分。我一直安慰自己桃焕,他們只是感情好,可當我...
    茶點故事閱讀 65,519評論 6 385
  • 文/花漫 我一把揭開白布欠窒。 她就那樣靜靜地躺著覆旭,像睡著了一般。 火紅的嫁衣襯著肌膚如雪岖妄。 梳的紋絲不亂的頭發(fā)上型将,一...
    開封第一講書人閱讀 49,792評論 1 290
  • 那天,我揣著相機與錄音荐虐,去河邊找鬼七兜。 笑死,一個胖子當著我的面吹牛福扬,可吹牛的內(nèi)容都是我干的腕铸。 我是一名探鬼主播,決...
    沈念sama閱讀 38,933評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼铛碑,長吁一口氣:“原來是場噩夢啊……” “哼狠裹!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起汽烦,我...
    開封第一講書人閱讀 37,701評論 0 266
  • 序言:老撾萬榮一對情侶失蹤涛菠,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后撇吞,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體俗冻,經(jīng)...
    沈念sama閱讀 44,143評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,488評論 2 327
  • 正文 我和宋清朗相戀三年牍颈,在試婚紗的時候發(fā)現(xiàn)自己被綠了迄薄。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片湃缎。...
    茶點故事閱讀 38,626評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡唉匾,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出篷角,到底是詐尸還是另有隱情画机,我是刑警寧澤冶伞,帶...
    沈念sama閱讀 34,292評論 4 329
  • 正文 年R本政府宣布,位于F島的核電站色罚,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏账劲。R本人自食惡果不足惜戳护,卻給世界環(huán)境...
    茶點故事閱讀 39,896評論 3 313
  • 文/蒙蒙 一金抡、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧腌且,春花似錦梗肝、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,742評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至精续,卻和暖如春坝锰,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背重付。 一陣腳步聲響...
    開封第一講書人閱讀 31,977評論 1 265
  • 我被黑心中介騙來泰國打工顷级, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人确垫。 一個月前我還...
    沈念sama閱讀 46,324評論 2 360
  • 正文 我出身青樓弓颈,卻偏偏與公主長得像,于是被迫代替她去往敵國和親删掀。 傳聞我的和親對象是個殘疾皇子翔冀,可洞房花燭夜當晚...
    茶點故事閱讀 43,494評論 2 348