golang通道channel的用法及特性

定義

通道是go語(yǔ)言的一種數(shù)據(jù)類(lèi)型,是goroutine之間的通信機(jī)制。

初始化
var c chan TYPE
ch := make(chan int)  //無(wú)緩沖通道
ch := make(chan string ,10) //有緩沖通道
ch := make(chan<- string) //只能用于接收的通道 單向通道
ch := make(<-chan float64) //只能用于發(fā)送的通道 單項(xiàng)通道
接收元素

從一個(gè)未初始化的通道中獲取數(shù)據(jù)會(huì)永遠(yuǎn)阻塞。
從一個(gè)已關(guān)閉的通道中獲取數(shù)據(jù),如果通道中還有值可以正常獲取,如果通道中沒(méi)有值,會(huì)得到該通道類(lèi)型的零值。
從一個(gè)沒(méi)有值的通道中獲取數(shù)據(jù)會(huì)被阻塞,直到通道被寫(xiě)入數(shù)據(jù)或者關(guān)閉。

strChan := make(chan string,3)
elem := <-strChan
elem ,ok := <-strChan
發(fā)送元素

向一個(gè)未初始化的通道中寫(xiě)入數(shù)據(jù)會(huì)永遠(yuǎn)阻塞。
向一個(gè)無(wú)緩沖的通道中寫(xiě)入數(shù)據(jù)會(huì)被終阻塞,直到該通道有至少一個(gè)接收操作進(jìn)行為止,發(fā)送操作才能被喚醒。
向一個(gè)已關(guān)閉的通道寫(xiě)入數(shù)據(jù)會(huì)引起恐慌。所以不要在接收方去關(guān)閉一個(gè)通道。
向一個(gè)已滿(mǎn)的通道寫(xiě)入數(shù)據(jù)也會(huì)被阻塞,直到有接收操作完成才能被喚醒。

strChan := make(chan string,3)
strChan<-"hello"
strChan<-"world"

用法

for與channel

for的range子句可以對(duì)通道進(jìn)行讀取操作

var ch = make(chan int)
for e:= range ch{
   fmt.Printf("element:%d",e)
}

for語(yǔ)句可以把通道已有的數(shù)據(jù)按順序讀出。當(dāng)通道沒(méi)有數(shù)據(jù)時(shí),for語(yǔ)句會(huì)被阻塞在range子句處。

select與channel

select語(yǔ)句是一種僅能用于通道發(fā)送和接收的語(yǔ)句。一條select語(yǔ)句執(zhí)行時(shí)會(huì)選擇其中的一個(gè)分支并執(zhí)行。

var intChan = make(chan int,10)
var strChan = make(chan string,10)
select{
case e:=<-intChan:
    fmt.Printf("this case wad selected,element = %v",e)
case e:=<-strChan:
    fmt.Printf("this case wad selected,element = %v",e)
 default:
    fmt.Println("default")

如果同時(shí)又多個(gè)case可以被觸發(fā),select會(huì)通過(guò)偽隨機(jī)的算法隨機(jī)選擇一個(gè)case并執(zhí)行。

timer與channel
定時(shí)器

time.Timer是time包提供的定時(shí)器。它可以在到達(dá)指定時(shí)間后發(fā)送一個(gè)元素到字段C中

timer := time.NewTimer(time.Second * 10)
fmt.Printf("now:%v",time.Now)
expiration := <-timer.C
fmt.Printf("now:%v",time.Now)

timer.C在10s之后才會(huì)有元素輸出,expiration定義語(yǔ)句一直被阻塞,直到10s后,才能打印第二條語(yǔ)句。

expiration := <-time.After(time.Second * 10)

與timer是等價(jià)了,簡(jiǎn)化了timer的定義。

斷續(xù)器

time.Tricker是time包提供的斷續(xù)器,它能按指定時(shí)間間隔不斷重復(fù)的發(fā)送元素到字段通道C中,當(dāng)下一次間隔時(shí)間點(diǎn)到來(lái)之時(shí),通道中還能沒(méi)被取出的元素,則當(dāng)前本次操作就會(huì)被立即取消。

var ch = make(chan int 3)
ticker := time.NewTricker(time.Second )
for _ = range ticker.C{
    select {
    case ch <- 1:
    case ch <- 2:
    case ch <- 3:
    }
 }

特性

并發(fā)安全

channel的數(shù)據(jù)結(jié)構(gòu)如下:

type hchan struct {
    qcount   uint           // 數(shù)組長(zhǎng)度,即已有元素個(gè)數(shù)
    dataqsiz uint           // 數(shù)組容量,即可容納元素個(gè)數(shù)
    buf      unsafe.Pointer // 數(shù)組地址
    elemsize uint16         // 元素大小
    closed   uint32
    elemtype *_type // 元素類(lèi)型
    sendx    uint   // 下一次寫(xiě)下標(biāo)位置
    recvx    uint   // 下一次讀下標(biāo)位置
    recvq    waitq  // 讀等待隊(duì)列
    sendq    waitq  // 寫(xiě)等待隊(duì)列
    lock     mutex
}

lock保證了chan的多進(jìn)程之間的并發(fā)安全。

同步與異步

無(wú)緩沖通道同步
有緩沖通道異步

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀(guān)點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容