Go channel 关闭和广播
Dont Communicate by sharing memory, sharing memory by communicate. 不要通过共享内存的方式通讯,要通过通讯的方式共享内存
Channel 基本概念
一个通道相当于 FIFO 的队列, 通道中各个元素之间都是严格按照发送的顺序队列,先发送的队列一定会被先接收,元素值的发送和传输和发送都使用到操作符 <-
channel 的关闭
- 向关闭的 channel 发送数据, 会导致 panic
package main import ( "fmt" "sync" "testing" ) func dataProducer(ch chan int, wg *sync.WaitGroup) { go func() { for i := 0; i < 11; i++ { ch <- i } wg.Done() }() } func dataConsumer(ch chan int , wg *sync.WaitGroup) { go func () { for i := 0; i < 10; i++ { data := <- ch fmt.Println(data) } close(ch) wg.Done() }() } func TestCloseChanner(t *testing.T) { var wg sync.WaitGroup ch := make(chan int) wg.Add(1) dataProducer(ch, &wg) wg.Add(1) dataConsumer(ch, &wg) wg.Wait() }
运行结果
GOROOT=C:\Go #gosetup GOPATH=D:\GoWorkSpace #gosetup C:\Go\bin\go.exe test -c -o C:\Users\wangm\AppData\Local\Temp\___channel_close_test_go.exe GoProject/src/main/gobase/channel #gosetup C:\Go\bin\go.exe tool test2json -t C:\Users\wangm\AppData\Local\Temp\___channel_close_test_go.exe -test.v -test.run ^\QTestCloseChanner\E$ #gosetup === RUN TestCloseChanner 0 1 2 3 4 5 6 7 8 9 panic: send on closed channel goroutine 20 [running]: GoProject/src/main/gobase/channel.dataProducer.func1(0xc0000862a0, 0xc0000942b0) D:/GoWorkspaces/GoProject/src/main/gobase/channel/channel_close_test.go:12 +0x4a created by GoProject/src/main/gobase/channel.dataProducer D:/GoWorkspaces/GoProject/src/main/gobase/channel/channel_close_test.go:10 +0x50 Process finished with exit code 1
- v, ok <- ch; ok 为 bool 值, true 表示正常接收,false 表示通道关闭
- 所有的 channel 接收者都会在 channel 关闭时,立刻从阻塞等待中返回且上述 ok 值 为 false 。这个广播机制被利用,进行多个订阅同时发送信号。
package main import ( "fmt" "sync" "testing" ) func dataProducer(ch chan int, wg *sync.WaitGroup) { go func() { for i := 0; i < 10; i++ { ch <- i } close(ch) wg.Done() }() } func dataConsumer(ch chan int , wg *sync.WaitGroup) { go func () { for i := 0; i < 10; i++ { if data, ok := <- ch; ok { fmt.Println(data) } else { break } } wg.Done() }() } func TestCloseChanner(t *testing.T) { var wg sync.WaitGroup ch := make(chan int) wg.Add(1) dataProducer(ch, &wg) wg.Add(1) dataConsumer(ch, &wg) wg.Wait() }
运行结果
GOROOT=C:\Go #gosetup GOPATH=D:\GoWorkSpace #gosetup C:\Go\bin\go.exe test -c -o C:\Users\wangm\AppData\Local\Temp\___channel_close_test_go.exe GoProject/src/main/gobase/channel #gosetup C:\Go\bin\go.exe tool test2json -t C:\Users\wangm\AppData\Local\Temp\___channel_close_test_go.exe -test.v -test.run ^\QTestCloseChanner\E$ #gosetup === RUN TestCloseChanner 0 1 2 3 4 5 6 7 8 9 --- PASS: TestCloseChanner (0.00s) PASS Process finished with exit code 0
测试代码
package main import ( "fmt" "sync" "testing" ) func dataProducer(ch chan int, wg *sync.WaitGroup) { go func() { for i := 0; i < 10; i++ { ch <- i } close(ch) wg.Done() }() } func dataConsumer(ch chan int , wg *sync.WaitGroup) { go func () { for i := 0; i < 11; i++ { data := <- ch fmt.Println(data) } wg.Done() }() } func TestCloseChanner(t *testing.T) { var wg sync.WaitGroup ch := make(chan int) wg.Add(1) dataProducer(ch, &wg) wg.Add(1) dataConsumer(ch, &wg) wg.Wait() }
运行结果:
GOPATH=D:\GoWorkSpace #gosetup C:\Go\bin\go.exe test -c -o C:\Users\wangm\AppData\Local\Temp\___channel_close_test_go.exe GoProject/src/main/gobase/channel #gosetup C:\Go\bin\go.exe tool test2json -t C:\Users\wangm\AppData\Local\Temp\___channel_close_test_go.exe -test.v -test.run ^\QTestCloseChanner\E$ #gosetup === RUN TestCloseChanner 0 1 2 3 4 5 6 7 8 9 0 --- PASS: TestCloseChanner (0.00s) PASS Process finished with exit code 0