通道(channel)
生活随笔
收集整理的這篇文章主要介紹了
通道(channel)
小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
描述
- 主要用于多個(gè)goroutine間傳遞數(shù)據(jù).一個(gè)通道相當(dāng)于一個(gè)先進(jìn)先出(FIFO)的隊(duì)列.
- channel用來在協(xié)程[goroutine]之前傳遞數(shù)據(jù),準(zhǔn)確的說,是用來傳遞數(shù)據(jù)的所有權(quán)。
- 一個(gè)設(shè)計(jì)良好的程序應(yīng)該確保同一時(shí)刻channel里面的數(shù)據(jù)只會被同一個(gè)協(xié)程擁有,這樣就可以避免并發(fā)帶來的數(shù)據(jù)不安全問題[data races]。
- 官方的go編譯器限制channel最多能容納到65535個(gè)元素,但我們不宜傳遞體積過大的元素值,因?yàn)閏hannel的數(shù)據(jù)從進(jìn)入到流出會涉及到數(shù)據(jù)拷貝操作。如果元素體積過大,最好的方法還是使用傳遞指針來取代傳遞值。
內(nèi)部結(jié)構(gòu)
每個(gè)channel內(nèi)部實(shí)現(xiàn)都有三個(gè)隊(duì)列。
- 接收消息的協(xié)程隊(duì)列。
這個(gè)隊(duì)列的結(jié)構(gòu)是一個(gè)限定最大長度的鏈表,所有阻塞在channel的接收操作的協(xié)程都會被放在這個(gè)隊(duì)列里。 - 發(fā)送消息的協(xié)程隊(duì)列。
這個(gè)隊(duì)列的結(jié)構(gòu)也是一個(gè)限定最大長度的鏈表。所有阻塞在channel的發(fā)送操作的協(xié)程也都會被放在這個(gè)隊(duì)列里。 - 環(huán)形數(shù)據(jù)緩沖隊(duì)列。
這個(gè)環(huán)形數(shù)組的大小就是channel的容量。如果數(shù)組裝滿了,就表示channel滿了,如果數(shù)組里一個(gè)值也沒有,就表示channel是空的。 - 對于一個(gè)阻塞型channel來說,它總是同時(shí)處于即滿又空的狀態(tài)。一個(gè)channel被所有使用它的協(xié)程所引用,也就是說,只要這兩個(gè)裝了協(xié)程的隊(duì)列長度大于零,那么這個(gè)channel就永遠(yuǎn)不會被垃圾回收。另外,協(xié)程本身如果阻塞在channel的讀寫操作上,這個(gè)協(xié)程也永遠(yuǎn)不會被垃圾回收。
分類
- 非緩沖通道
make的時(shí)候第二個(gè)參數(shù)為0或者不填.
無論是發(fā)送操作還是接收操作,一開始執(zhí)行就會被阻塞,直到配對的操作也開始執(zhí)行才會繼續(xù)傳遞。由此可見,非緩沖通道是在用同步的方式傳遞數(shù)據(jù)。也就是說,只有收發(fā)雙方對接上了,數(shù)據(jù)才會被傳遞.數(shù)據(jù)是直接從發(fā)送方復(fù)制到接收方的,中間并不會用非緩沖通道做中轉(zhuǎn)
- 緩沖通道
make 的時(shí)候第一個(gè)參數(shù)大于0.
在有容量的時(shí)候,發(fā)送和接收是不會互相依賴的.用異步的方式傳遞數(shù)據(jù)。
特性
- 是類型安全的
- 發(fā)送操作之間是互斥的,接收操作之間也是互斥的(多線程安全)
- 進(jìn)入通道的并不是在接收操作符右邊的那個(gè)元素值,而是它的副本
- 移出通道的是通道元素的副本
- channel關(guān)閉后,如果還有數(shù)據(jù)還是可以正常讀取的,等讀取完后,v,ok := <- ch,其中ok是false,v是對應(yīng)類型的零值
- 通道會阻塞goroutine
- 關(guān)閉一個(gè)只讀channel是非法的,編譯器直接報(bào)錯(cuò)
- 使用 v, ok <- ch 接收一個(gè)值。第二個(gè)遍歷ok是可選的,它表示channel是否已關(guān)閉。接收值只會又兩種結(jié)果,要么成功要么阻塞,而永遠(yuǎn)也不會引發(fā)panic
- 不同于array/slice/map上的for-range,channel的for-range只允許有一個(gè)變量
阻塞的Case
- 通道容量已滿情況,執(zhí)行寫入
- 通道沒有數(shù)據(jù),執(zhí)行讀取
- 對于值為nil的通道,不論它的具體類型是什么,對它的發(fā)送操作和接收操作都會永久地處于阻塞狀態(tài)。它們所屬的 goroutine 中的任何代碼,都不再會被執(zhí)行.
- 對于值為nil的通道,若程序只有一個(gè)goroutine,向其中發(fā)送數(shù)據(jù)或接收數(shù)據(jù),都會阻塞,程序會死鎖;若程序有多個(gè)goroutine,只會阻塞那個(gè)向nil通道發(fā)送或接收數(shù)據(jù)的goroutine,程序不會panic
panic的Case
- 關(guān)閉已經(jīng)關(guān)閉的channel
- 已經(jīng)關(guān)閉的channel發(fā)送數(shù)據(jù)
單向通道
make(chan<- int, 1) make(<-chan int, 1)- 作用
a.作為函數(shù)參數(shù),從而約束函數(shù)體內(nèi)的行為;
b.作為函數(shù)返回值,從而約束返回后的行為;
正常通道關(guān)閉
-
從channel的接收協(xié)程隊(duì)列中移除所有的goroutine,并喚醒它們。
-
從channel的接收協(xié)程隊(duì)列中移除所有的goroutine,并喚醒它們。
-
一個(gè)已關(guān)閉的channel內(nèi)部的緩沖數(shù)組可能不是空的,沒有接收的這些值會導(dǎo)致channel對象永遠(yuǎn)不會被垃圾回收。
總結(jié)
- 如果channel關(guān)閉了,那么它的接收和發(fā)送協(xié)程隊(duì)列必然空了,但是它的緩沖數(shù)組可能還沒有空。
- channel的接收協(xié)程隊(duì)列和緩沖數(shù)組,同一個(gè)時(shí)間必然有一個(gè)是空的
- channel的緩沖數(shù)組如果未滿,那么它的發(fā)送協(xié)程隊(duì)列必然是空的
- 對于緩沖型channel,同一時(shí)間它的接收和發(fā)送協(xié)程隊(duì)列,必然有一個(gè)是空的
- 對于非緩沖型channel,一般來說同一時(shí)間它的接收和發(fā)送協(xié)程隊(duì)列,也必然有一個(gè)是空的,但是有一個(gè)例外,那就是當(dāng)它的發(fā)送操作和接收操作在同一個(gè)select塊里出現(xiàn)的時(shí)候,兩個(gè)隊(duì)列都不是空的。
總結(jié)
以上是生活随笔為你收集整理的通道(channel)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: python破解md5_python怎么
- 下一篇: unity pdg 设置隐藏不需要的节点