为什么我的代码在从通道读取时会死锁(随后崩溃),我希望在完全读取通道后它会在读取时阻塞,但不会崩溃。我知道这是一个死锁状态,因为没有人正在写入通道并读取该通道上的块。
如何更改代码以读取所有频道内容,然后从main退出而不是崩溃。
去游乐场: https://play.golang.org/p/rjXZZOx1FFZ
package main
import (
"fmt"
"sync"
)
func main() {
var wg sync.WaitGroup
news := make(chan int, 10)
wg.Add(1)
go foo(&wg, news)
wg.Wait()
for {
fmt.Printf("reading: %v\n", <-news)
//crashes here after printing 0-9
}
}
func foo(wg *sync.WaitGroup, news chan int) {
for i:=0; i<10;i++ {
fmt.Printf("Writing\n")
news <- i
}
(*wg).Done()
}
答案 0 :(得分:2)
程序死锁是因为通道上的主要块已接收并且没有其他goroutines将发送到该通道。
使用这种方法读取所有频道内容,然后从main退出:main读取频道直到关闭; foo写入所有值并关闭通道。
func main() {
news := make(chan int, 10)
go foo(news)
// range breaks when the channel is closed
for v := range news {
fmt.Printf("reading: %v\n", v)
}
}
func foo(news chan int) {
for i := 0; i < 10; i++ {
fmt.Printf("Writing\n")
news <- i
}
// close channel to indicate that no more values will be sent.
close(news)
}
答案 1 :(得分:2)
为解释这种情况的发生原因,您从恐慌中得到的错误消息告诉您它的要旨:
fatal error: all goroutines are asleep - deadlock!
您无法让所有goroutine都在等待其他goroutine执行某项操作。在这种情况下,当运行foo
的goroutine完成并且运行main
的goroutine收到了发送到news
通道的所有消息(0至9)后,您的程序剩下一个goroutine,等待在频道上接收消息,因为再也没有其他goroutine可以这样做,所以永远不会再有消息发送给它。
答案 2 :(得分:1)
代码由于死锁而崩溃。
fatal error: all goroutines are asleep - deadlock!
原始代码有两个有趣的问题。
如果您在foo
goroutine中关闭新闻频道而不是死锁,您将永远在main
中运行无限循环。
对2个简单的代码进行更改应该会使这一点更加清楚,并使其在处理news
个项目之后退出。
https://play.golang.org/p/qSU7sV7Wrov
package main
import (
"fmt"
"sync"
)
func main() {
var wg sync.WaitGroup
news := make(chan int, 10)
wg.Add(1)
go foo(&wg, news)
wg.Wait()
for n := range news {
fmt.Printf("reading: %v\n", n)
}
fmt.Println("We're out of news!")
}
func foo(wg *sync.WaitGroup, news chan int) {
for i := 0; i < 10; i++ {
fmt.Printf("Writing\n")
news <- i
}
close(news)
wg.Done()
}
当然,您可以在不使用WaitGroups的情况下重写它,而只需使用其他人指出的通道,这可能是一个更优雅的解决方案。