我有一段代码根据我如何放置close
调用和位置来尝试理解
func main() {
ch := make(chan int, 2)
go func(ch chan int) {
for i := 1; i <= 5; i++ {
ch <- i
fmt.Println("Func goroutine sends data: ", i)
}
//Pos1 - Works perfectly
//close(ch)
}(ch)
fmt.Println("Main goroutine sleeps 2 seconds")
time.Sleep(time.Second * 2)
fmt.Println("Main goroutine begins receiving data")
//Pos2 - Puts in only 2 ints 1 and 2 and then prints only that
//close(ch)
for d := range ch {
fmt.Println("Main goroutine received data:", d)
}
//Pos3 - Throws fatal error
close(ch)
}
我一直试图了解和阅读有关此的博客,但仍然无法理解某些内容
close
在这个位置上工作?for loop
试图向关闭的通道写入更多元素时为什么不抛出异常? / li>
fatal error: all goroutines are asleep - deadlock!
。为什么会这样?答案 0 :(得分:3)
但是我想在缓冲通道上进行范围调整,范围函数必须事先知道要迭代多少个元素,并且必须关闭该通道。
这种假设是错误的,并且是所有误解的根源。
Go Spec中描述了在通道上进行测距的行为:https://golang.org/ref/spec#For_statements
对于通道,所产生的迭代值是通道上发送的连续值,直到通道关闭为止。如果通道为nil,则范围表达式将永远阻塞。
当评估for语句并且该语句不需要知道元素数时,不需要关闭通道。
因此,在您的代码中,将$ cat file2.txt
This is a tale
Of Captain Jack Sparrow
A Pirate So Brave
On the Seven Seas.
放入Pos1中,确实是正确的方法。当您将其放入Pos3中时,for循环将等待通道关闭,这只能在for循环本身之后发生,因此它是一个死锁。
将close
放在Pos2中是有问题的,而且行为有些棘手。可能会出现 错误,但也可能只输出两个数字。这是因为在for循环之前关闭通道时,循环可以无阻塞运行,然后close
返回。当main()
返回时,Go程序结束。是否引发错误仅取决于调度程序是否在进程之间切换到goroutine,这不能保证。