goroutine和goroutine之間通過channel通信
channel的創建
1 使用make創建
channel創建可以用make方法,如:
c := make(chan int)
此外,如果make方法第二個參數多寫一個數字,則表示對channel作buffer緩衝:
// 表示channel中每接收3個後再給接收者
c := make(chan int, 3)
2 使用var創建
不用make的話,也可以用var:
var c chan int // 此時c爲nil
如果創建channel數組,則寫法如下:
var channels [10]chan int
channel的傳與收
往創建好的channel中傳數據使用<-表示,如:
c <- 1
c <- 2
注意:往channel傳數據後必須要有接收者,否則程序運行會報deadlock
較完整的示例片段如下:
// 創建一個channel
c := make(chan int)
// 起一個goroutine,用來接收channel中的數據並打印
go func() {
for {
n := <-c
fmt.Println(n)
}
}()
// 向channel中傳數據
c <- 1
c <- 2
// 這裏加個sleep,是爲了避免channel中的數據還沒打印,main函數就退出了
time.Sleep(time.Millisecond)
channel可作參數和返回值
channel可以作爲參數傳遞,也可以作返回值。
需要注意的是,channel作爲收數據還是發數據,寫法是不一樣的。
chan<- int 和<-chan int這兩個是有區別的:
- chan<- int表示send only,只能往裏發
- <-chan int表示revice only,只能從裏收
channel的close
發送方可以使用close©方法來關閉channel,以告訴接收方沒有新數據了。
channel關閉後,接收者還能接收數據不會報錯,不過接收到的是對應類型的零值
如何判斷channel是否關閉?
方法(1): 通過if判斷
n, ok := <-c
if !ok {
fmt.Println("channel 沒有數據了")
break
}
方法(2): 通過range
for n := range c {
...
}
使用sync.WaitGroup等待goroutine任務結束
之前使用time.Sleep(time.Millisecond)的方式來讓main函數等待任務完成,但是不太好。
golang中提供了sync.WaitGroup方法來實現這個功能
例:
package main
import (
"fmt"
"sync"
)
func doWork(id int,
w worker) {
for n := range w.in {
fmt.Printf("Worker %d received %c\n",
id, n)
w.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)
}
wg.Add(20)
for i, worker := range workers {
worker.in <- 'a' + i
}
for i, worker := range workers {
worker.in <- 'A' + i
}
wg.Wait()
}
func main() {
chanDemo()
}
select的使用
例:
var c1, c2 chan int
select {
case n := <-c1:
fmt.Println("received from c1:", n)
case n := <-c2:
fmt.Println("received from c2:", n)
default:
fmt.Println("no value received")
}
注意:通過var方式聲明的c1和c2默認是nil,但用select方式並不會報錯,因爲有default兜底。
如果這裏沒有default,程序則會報deadlock,因爲這裏只有接收者,沒有channel的發送者