go语言学习笔记——channel的关闭和广播

397 阅读1分钟

channel的使用场景,经常是不同协程之间的通信,一个协程写数据,另外的一个协程读取数据。这个时候就需要协程之间的广播机制。

原始代码:

func dataProduce(ch chan int, wg *sync.WaitGroup) {
	go func() {
		for i := 0; i < 10; i++ {
			ch <- i
		}
		wg.Done()
	}()

}

func dataConsume(ch chan int, wg *sync.WaitGroup) {
	go func() {
		for i := 0; i < 10; i++ {
			data := <-ch
			fmt.Printf("输出data=%d \n", data)
		}
		wg.Done()
	}()
}

func TestChannel(t *testing.T) {
	var wg sync.WaitGroup
	ch1 := make(chan int)
	wg.Add(1)
	dataProduce(ch1, &wg)
	wg.Add(1)
	dataConsume(ch1, &wg)
	wg.Wait()
}

执行TestChannel的函数,代码会输出

=== RUN   TestChannel
输出data=0 
输出data=1 
输出data=2 
输出data=3 
输出data=4 
输出data=5 
输出data=6 
输出data=7 
输出data=8 
输出data=9 
--- PASS: TestChannel (0.00s)
PASS

这个时候是事先约定了数据的个数,其实可以通过广播的形式,拿到写协程的状态,自动做处理。

在读取channel的时候,会有两个返回值

data, ok := <-ch
data: 在channel读取的数据
ok: 如果为true,表示写数据的channel没有关闭;false表示写数据的channel已经关闭

优化一下逻辑

func TestChannel(t *testing.T) {
	var wg sync.WaitGroup
	ch1 := make(chan int)
	wg.Add(1)
	dataProduce2(ch1, &wg)
	wg.Add(1)
	dataConsume2(ch1, &wg)
	wg.Wait()
}

func dataProduce2(ch chan int, wg *sync.WaitGroup) {
	go func() {
		for i := 0; i < 10; i++ {
			ch <- i
		}
		close(ch)
		wg.Done()
	}()
}

func dataConsume2(ch chan int, wg *sync.WaitGroup) {
	go func() {
		for true {
			if data, ok := <-ch; ok {
				fmt.Printf("输出data=%d \n", data)
			} else {
				fmt.Println("produce channel has closed.")
				break
			}
		}
		wg.Done()
	}()
}

输出结果

=== RUN   TestChannel
输出data=0 
输出data=1 
输出data=2 
输出data=3 
输出data=4 
输出data=5 
输出data=6 
输出data=7 
输出data=8 
输出data=9 
produce channel has closed.
--- PASS: TestChannel (0.00s)
PASS