go 语言通道 channel - 关闭通道避免不对称取值

问题描述

假设我们会利用协程向通道内添加动态数量的数据,然后我们利用循环一直取出数据,直至取完。

错误的代码 :

package main

func main() {
	ch := make(chan int)
	// 开启一个协程
	go func() {
		for i := 1; i <= 10; i++ {
			ch <- i
		}

	}()

	for {
	    // 此处因为管道没有关闭,会产生阻塞
		res, ok := <-ch
		if ok {
			println(res)
		} else {
			break
		}
	}
	println("主进程结束")
}

上面的代码中,我们并不知道何时取完数据,然后 for 循环在取出 10 条数据后报错!

1
2
3
4
5
6
7
8
9
10
fatal error: all goroutines are asleep - deadlock!

关闭管道让取出动作可以识别:

package main

func main() {
	ch := make(chan int)
	// 开启一个协程
	go func() {
		for i := 1; i <= 10; i++ {
			ch <- i
		}
		close(ch)
	}()

	for {
		res, ok := <-ch
		if ok {
			println(res)
		} else {
			break
		}
	}
	println("主进程结束")
}

在上面的代码中,我们使用 close 函数关闭了通道,这样 res,ok := <-ch 代码运行,当管道关闭时 ok 的值会为 false,我们利用 break 跳出循环,逻辑将不会阻塞。

当我们再次需要向 ch 中存入数据时,我们可以将 ch 赋值为一个新的通道:

ch = make(chan int)