如何解决使用频道时出现问题:所有goroutine都处于睡眠状态-死锁
我试图了解渠道的运作方式。我有这个例子:
import (
"fmt"
"runtime"
"time"
)
func greet(c chan string) {
fmt.Println("1: " + <-c)
fmt.Println("2: " + <-c)
}
func main() {
fmt.Println("main() started")
c := make(chan string,1)
go greet(c)
c <- "John"
c <- "Mike"
c <- "Mary"
fmt.Println("active goroutines",runtime.NumGoroutine())
c <- "Edward"
time.Sleep(time.Second)
fmt.Println("main() stopped")
}
在执行上述代码时,我看到它给出了一个错误“致命错误:所有goroutine都在睡眠-死锁!”。但是据我了解,在“爱德华”发送到频道后,执行应该被阻塞。
c <- "Edward"
,该程序应已打印出Mary和Edward的值。我也不会在任何地方关闭此频道。谁能告诉我原因,我该如何解决?
解决方法
请参考以下代码,以便您更好地理解它。我也添加了评论。虽然@mkopriva消除了您的疑虑,但我认为如果发布带有注释的代码会更好。
package main
import (
"fmt"
"time"
)
func greet(c chan string) {
// Range over the channel until close() is called
for r := range c {
// Print the names
fmt.Println(r)
}
}
func main() {
fmt.Println("main() started")
c := make(chan string,1) // Make a bufferred channel with capacity of 1
go greet(c) // Spawn the goroutine
c <- "John" // Send
c <- "Mike" // Send
c <- "Mary" // Send
c <- "Edward" // Send
close(c) // Close the channel which signals the for loop
// inside greet to stop receiving
time.Sleep(2 * time.Second) // Let us give the main gorutine some time
// before it exits so that it lets the greet() to recieve all the names.
// But it's better to use sync.WaitGroup for this.
fmt.Println("main() stopped")
}
,
问题的答案非常简单。
如果您将某些内容放入频道,则必须以某种方式将其撤回。
只要在函数greet(c chan string)
前面加一个“ go”,它就不会无限运行。这仅表示该函数正在调用新的go例程以在其中运行。
您编写的代码会产生死锁,因为该函数在通道范围内终止后终止。
go greet(c)
c <- "John"
c <- "Mike"
//all these things happen at the same time
当您将某个内容放到无法再次退出的频道中时,就会创建一个死锁。该线程尝试将某些东西放到不再有使用者的渠道中。
解决方案也非常简单。只需在频道上循环即可。这样,它会在整个通道上一直传播,直到关闭为止。
func greet(c chan string) {
for name := range c {
fmt.Println(name)
}
}
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。