上篇文章介紹了channel的資料結構,這篇文章就不在過多講述了
先來了解一下單向channel是如何實現的
- channel可以透過引數傳遞,單向channel只是對channel的一種使用限制,就這跟C語言使用const修飾函式引數為只讀是一個道理的
- func readChan(chanName <-chan int);透過形參限定函式內部只能從channel中讀取資料
- func writeChan(chanName chan<- int);透過形參限定函式內部只能向channel中寫入資料
- 下面用簡單的程式碼演示一個簡單的示例程式:
func readChan(chanName <-chan int) { <- chanName } func writeChan(chanName chan<- int) { chanName <- 1 7. } func main() { var mychan = make(chan int, 10) writeChan(mychan) readChan(mychan) }
- 上面的程式碼可以看出mychan是個正常的channel,而readChan()引數限制了傳入的channel只能用來讀,writeChan()引數限制了傳 入的channel只能用來寫,這樣就實現了單向管道的簡單使用。
使用select可以監控多channel,比如監控多個channel,當其中某一個channel有資料時,就從其讀出資料。
package main
import (
"fmt"
"time"
)
func addNumberToChan(chanName chan int) {
for {
chanName <- 1time.Sleep(1 * time.Second)
}
}
func main() {
var chan1 = make(chan int, 10)
var chan2 = make(chan int, 10)
go addNumberToChan(chan1)
go addNumberToChan(chan2)
for {
select {
case e := <- chan1:
fmt.Printf("Get element from chan1: %d\n", e)
case e := <- chan2:
fmt.Printf("Get element from chan2: %d\n", e)
default:
fmt.Printf("No element in chan1 and chan2.\n")
time.Sleep(1 * time.Second)
}
}
}
以上程式中建立兩個channel:chan1和chan2。函式addNumberToChan()函式會向兩個channel中週期性寫入數 據。透過select可以監控兩個channel,任意一個可讀時就從其中讀出資料,想知道程式如何輸入可以把程式碼複製到編輯器中執行一下就知道了哈,這裡就不貼執行後的結果了,不過可以知道的是上面的程式從channel中讀出資料的順序是隨機的,事實上select語句的多個case執行順序是隨機的
關於select的執行原理是這樣的,select的case語句讀channel不會阻塞,儘管channel中沒有資料。這是由於case語句編譯後呼叫讀channel時會明確傳入不阻塞的引數,此時讀不到資料時不會將當前goroutine加入到等待佇列,而是直接返回,select資料結構方面我還在研究,後面出一遍文章進行講解。
透過range可以持續從channel中讀出資料,就跟在遍歷一個陣列一樣,當channel中沒有資料時會阻塞當前goroutine,與讀channel時阻塞處理機制一樣。
func chanRange(chanName chan int) {
for e := range chanName {
fmt.Printf("Get element from chan: %d\n", e)
}
}
以上程式在執行時需要注意:如果向此channel寫資料的goroutine退出時,系統檢測到這種情況後會panic,否則range將會永久阻塞。
這些是我本人整理的資料結合自身的理解寫出來的關於channel的單向用法和select,range的簡單用法,還有很多不足希望大家指點並留言告知,技術在於積累,摸索,分享,才能進步,希望這篇文章可以幫到有需要的夥伴吧
本作品採用《CC 協議》,轉載必須註明作者和本文連結