我试图了解渠道的运作方式。我有这个例子:
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的值。我也不会在任何地方关闭此频道。谁能告诉我原因,我该如何解决?
答案 0 :(得分:1)
请参考以下代码,以便您更好地理解它。我也添加了评论。虽然@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")
}
答案 1 :(得分:0)
问题的答案非常简单。
如果您将某些内容放入频道,则必须以某种方式将其撤回。
只要在函数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)
}
}