概念:通道Channels可被認爲是Goroutines通訊的管道。html
聲明:通道零值爲nil(沒有任何做用),故通道必須使用相似map和slice的方法來定義編程
a := make(chan int) 併發
data := <- a // read from channel a eg: chan <- //發送數據
a <- data // write to channel a eg: <-cjan// 接收數據
一個通道發送、接收數據默認是阻塞的。故一個數據被髮送到channel,在發送語句中被阻塞,直到另外一個Goroutineapp
來接收。接收數據也相似。編程語言
通道的特性是幫助Goroutines有效地進行通訊,而無需像使用其餘編程語言中很是常見的顯式鎖或條件變量。函數
Channel的理論基礎是CSP,Go語言的併發基於CSP模型。不要經過共享內存來通訊,要經過通訊來共享內存。atom
channel是goroutine之間交互,發一個數據必須有另外一個goroutine去接收它。spa
例子1:channel發數據3d
func chanDemo(){ c := make(chan int) //這裏是開一個goroutine去接受發送的 若是沒有會報錯 go func() { for { n := <-c fmt.Println(n) } }() c <- 1 c <- 2 time.Sleep(time.Millisecond)//① } func main() { chanDemo() //若是沒有①則這裏輸出是1,由於雖然2發過去了可是來不及打印出來就結束了 }
相似函數同樣,一等公民,能夠做爲參數也可做爲返回值,能夠隨意的加參數。code
注:chan<- 說明是用來發送數據的,<-chan說明是用來接收數據的
例子2:channel.go
重點涉及:channel、buffered channel、range
//打印收到的數據 func worker(id int, c chan int) { for n := range c { fmt.Printf("Worker %d received %c\n", id, n) } } //建立channel 而後將其返回出去 chan<- int 用來發送數據 func createWorker(id int) chan<- int { c := make(chan int) go worker(id, c) //裏面的人用來收數據 return c } func chanDemo() { var channels [10]chan<- int for i := 0; i < 10; i++ { channels[i] = createWorker(i)//分發 } for i := 0; i < 10; i++ { //發送小a channels[i] <- 'a' + i } for i := 0; i < 10; i++ { channels[i] <- 'A' + i } time.Sleep(time.Millisecond) } func bufferedChannel() { c := make(chan int, 3)//channel發送以後必須有人收,這裏緩衝區是3 go worker(0, c) c <- 'a' c <- 'b' c <- 'c' c <- 'd' time.Sleep(time.Millisecond)//必需要加這個要否則沒有輸出哦 } //告訴接收方我發完數據啦 func channelClose() { c := make(chan int) go worker(0, c) c <- 'a' c <- 'b' c <- 'c' c <- 'd' close(c) time.Sleep(time.Millisecond) } func main() { fmt.Println("Channel as first-class citizen") chanDemo() fmt.Println("Buffered channel") bufferedChannel() fmt.Println("Channel close and range") channelClose() }
輸出是:
Channel as first-class citizen Worker 0 received a Worker 1 received b Worker 2 received c Worker 3 received d Worker 4 received e Worker 5 received f Worker 6 received g Worker 7 received h Worker 8 received i Worker 8 received I Worker 9 received j Worker 9 received J Worker 0 received A Worker 1 received B Worker 2 received C Worker 3 received D Worker 4 received E Worker 5 received F Worker 6 received G Worker 7 received H Buffered channel Worker 0 received a Worker 0 received b Worker 0 received c Worker 0 received d Channel close and range Worker 0 received a Worker 0 received b Worker 0 received c Worker 0 received d
使用Channel等待任務結束
func doWork(id int, w worker) { for n := range w.in { fmt.Printf("Worker %d received %c\n", id, n) w.done() //告訴別人我打印完啦 發送done } } type worker struct { in chan int done func() } func createWorker( id int, wg *sync.WaitGroup) worker { w := worker{ in: make(chan int), done: func() { wg.Done() }, } go doWork(id, w) return w } func chanDemo() { var wg sync.WaitGroup //併發 等待 var workers [10]worker for i := 0; i < 10; i++ { workers[i] = createWorker(i, &wg) //10個worker將 } wg.Add(20) //20個任務 for i, worker := range workers { worker.in <- 'a' + i } for i, worker := range workers { worker.in <- 'A' + i } wg.Wait() } func main() { chanDemo() }
https://www.cnblogs.com/ycx95/p/9361122.htm
用select進行調度
例子1:拿不到數據不會報錯,可是會進default,輸出是:No value received
channel中若是會進入非阻塞,能夠用select+default
func generator() chan int { out := make(chan int) go func() { i := 0 for { time.Sleep( time.Duration(rand.Intn(1500)) * time.Millisecond) out <- i i++ } }() return out } func worker(id int, c chan int) { for n := range c { time.Sleep(time.Second) fmt.Printf("Worker %d received %d\n", id, n) } } func createWorker(id int) chan<- int { c := make(chan int) go worker(id, c) return c } func main() { var c1, c2 = generator(), generator() var worker = createWorker(0) var values []int tm := time.After(10 * time.Second) tick := time.Tick(time.Second) for { var activeWorker chan<- int var activeValue int if len(values) > 0 { activeWorker = worker activeValue = values[0] } select { case n := <-c1: values = append(values, n) case n := <-c2: values = append(values, n) case activeWorker <- activeValue: values = values[1:] case <-time.After(800 * time.Millisecond): fmt.Println("timeout") case <-tick: fmt.Println( "queue len =", len(values)) case <-tm: fmt.Println("bye") return } } }
輸出結果:
queue len = 3 Worker 0 received 0 queue len = 5 Worker 0 received 0 queue len = 5 Worker 0 received 1 queue len = 10 Worker 0 received 1 queue len = 10 Worker 0 received 2 queue len = 11 Worker 0 received 2 queue len = 12 Worker 0 received 3 queue len = 13 Worker 0 received 3 queue len = 14 Worker 0 received 4 bye Process finished with exit code 0
這裏只是一個示例,詳情參見https://www.cnblogs.com/ycx95/p/9358739.html 的atomic.go
可是不建議。