// 单向只写通道
func writeONLY(c chan<- int) {
for i := 0; i < 10; i++ {
c <- i
}
}
// 单向只读通道
func readONLY(c <-chan int) {
for v := range c {
fmt.Println(v)
}
}
// 测试效果,调用test1()
func test1() {
ch1 := make(chan int, 10)
writeONLY(ch1)
//close(ch1)
readONLY(ch1)
}
0 1 2 3 4 5 6 7 8 9 fatal error: all goroutines are asleep - deadlock!
原因
在写完数据后没有关闭管道,导致在for-range遍历的时候协程阻塞了
解决方案
如果使用for-range遍历一定要记得写完数据后关闭通道
问题② ok-idiom线程阻塞// 单向只写通道
func writeONLY(c chan<- int) {
for i := 0; i < 10; i++ {
c <- i
}
}
// 用ok-idiom模式从管道中取值的话,写完数据后必须要关闭通道,否则阻塞
func readONLY2(c <-chan int) {
for {
v, ok := <-c
if !ok {
break
}
fmt.Println(v)
}
}
func test2() {
ch1 := make(chan int, 10)
writeONLY(ch1)
//close(ch1)
readONLY2(ch1)
}
0 1 2 3 4 5 6 7 8 9 fatal error: all goroutines are asleep - deadlock!
原因
ok-idiom的方式遍历和for-range一样,如果读不到管道中的数据会阻塞协程
解决方案
写完数据后关闭管道
问题③ fori遍历管道不阻塞,但死循环// 单向只写通道
func writeONLY(c chan<- int) {
for i := 0; i < 10; i++ {
c <- i
}
}
// 如果不关闭通道,还是可以从管道中读取类型的默认零值,无限循环的读
func readONLY3(c <-chan int) {
for {
v := <-c
fmt.Println(v)
}
}
func test3() {
ch1 := make(chan int, 10)
writeONLY(ch1)
//close(ch1)
readONLY3(ch1)
}
出现问题:死循环
原因
fori的方式循环从管道中取数据,如果管道中没有数据了,会从管道中读取管道类型的默认零值
解决方案
写完数据后关闭管道
总结for-range和ok-idiom的方式遍历如果不关闭管道会发生error,fori遍历会死循环
根据业务需求,写完数据后关闭管道是个好习惯