通道和等待组进入死锁
Channels and Wait Groups Entering Deadlock
我在处理 go 例程和让它们与主 go 例程上的频道通信时遇到问题。为了简化,我的代码看起来像这样:
func main() {
channel := make(chan string)
var wg sync.WaitGroup
for i := 0; i < 10; i++ {
wg.Add(1)
go performTest(channel, &wg, i)
}
wg.Wait()
close(channel)
for line := range channel {
fmt.Print(line)
}
}
func performTest(channel chan string, wg *sync.WaitGroup, i int) {
defer wg.Done()
// perform some work here
result := fmt.sprintf("Pretend result %d", i)
channel <- result
}
这似乎陷入了某种僵局,但我不明白为什么。它卡在 wg.Wait()
,尽管我希望一旦所有 goroutines 在等待组上调用 Done
它就会继续。我在这里错过了什么?我想等待 goroutines,然后迭代通道中的所有结果。
您可以在单独的go例程中等待组和关闭频道。如果通道关闭,您在通道上的范围将在收到最后发送的值后结束。
如果您只是等待,将不会从频道收到任何信息。由于通道是无缓冲的,performTest
goroutines 将无法发送。对于无缓冲通道,发送操作将阻塞,直到它被接收。因此,延迟的 wg.Done
调用永远不会发生,并且您的程序陷入僵局。由于 Done
仅在执行 forever-blocking 发送后调用。
func main() {
channel := make(chan string)
var wg sync.WaitGroup
for i := 0; i < 10; i++ {
wg.Add(1)
go performTest(channel, &wg, i)
}
// this is the trick
go func() {
wg.Wait()
close(channel)
}()
for line := range channel {
fmt.Print(line)
}
}
func performTest(channel chan string, wg *sync.WaitGroup, i int) {
defer wg.Done()
// perform some work here
result := fmt.Sprintf("Pretend result %d\n", i)
channel <- result
}
我在处理 go 例程和让它们与主 go 例程上的频道通信时遇到问题。为了简化,我的代码看起来像这样:
func main() {
channel := make(chan string)
var wg sync.WaitGroup
for i := 0; i < 10; i++ {
wg.Add(1)
go performTest(channel, &wg, i)
}
wg.Wait()
close(channel)
for line := range channel {
fmt.Print(line)
}
}
func performTest(channel chan string, wg *sync.WaitGroup, i int) {
defer wg.Done()
// perform some work here
result := fmt.sprintf("Pretend result %d", i)
channel <- result
}
这似乎陷入了某种僵局,但我不明白为什么。它卡在 wg.Wait()
,尽管我希望一旦所有 goroutines 在等待组上调用 Done
它就会继续。我在这里错过了什么?我想等待 goroutines,然后迭代通道中的所有结果。
您可以在单独的go例程中等待组和关闭频道。如果通道关闭,您在通道上的范围将在收到最后发送的值后结束。
如果您只是等待,将不会从频道收到任何信息。由于通道是无缓冲的,performTest
goroutines 将无法发送。对于无缓冲通道,发送操作将阻塞,直到它被接收。因此,延迟的 wg.Done
调用永远不会发生,并且您的程序陷入僵局。由于 Done
仅在执行 forever-blocking 发送后调用。
func main() {
channel := make(chan string)
var wg sync.WaitGroup
for i := 0; i < 10; i++ {
wg.Add(1)
go performTest(channel, &wg, i)
}
// this is the trick
go func() {
wg.Wait()
close(channel)
}()
for line := range channel {
fmt.Print(line)
}
}
func performTest(channel chan string, wg *sync.WaitGroup, i int) {
defer wg.Done()
// perform some work here
result := fmt.Sprintf("Pretend result %d\n", i)
channel <- result
}