英文:
Channels and Wait Groups Entering Deadlock
问题
我遇到了一些问题,无法控制goroutine并使它们返回到主goroutine上的通道。为了简化问题,我的代码大致如下:
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()
// 在这里执行一些工作
result := fmt.Sprintf("假装结果 %d", i)
channel <- result
}
这段代码似乎陷入了某种死锁状态,但我不明白为什么。它在wg.Wait()
处被阻塞,尽管我期望它在所有goroutine调用了Done
之后继续执行。我在这里漏掉了什么?我想等待goroutine完成,然后迭代通道中的所有结果。
英文:
I'm having trouble wrangling go routines and getting them to communicate back to a channel on the main go routine. To simplify, my code looks something like this:
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
}
This seems to enter into some kind of a deadlock, but I don't understand why. It gets stuck on wg.Wait()
, even though I would expect it to continue once all the goroutines have called Done
on the wait group. What am I missing here? I'd like to wait for the goroutines, and then iterate over all results in the channel.
答案1
得分: 2
你可以等待组并在单独的Go协程中关闭通道。如果通道关闭,那么在接收到最后一个发送的值之后,你的通道遍历将结束。
如果你只是等待,通道将不会接收任何内容。由于通道是无缓冲的,performTest
协程将无法发送。对于无缓冲的通道,发送操作将阻塞,直到接收方接收到该值。因此,延迟的 wg.Done
调用永远不会发生,你的程序将发生死锁。因为 Done
只有在永久阻塞的发送操作执行后才会被调用。
func main() {
channel := make(chan string)
var wg sync.WaitGroup
for i := 0; i < 10; i++ {
wg.Add(1)
go performTest(channel, &wg, i)
}
// 这是一个技巧
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()
// 在这里执行一些工作
result := fmt.Sprintf("假装的结果 %d\n", i)
channel <- result
}
https://play.golang.com/p/5pACJzwL4Hi
英文:
You can wait for the group and close the channel in a separate go routine. If the channel is closed, your range over the channel will end after the last sent value has been received.
If you just wait, nothing will receive from the channel. Since the channel is unbuffered, the performTest
goroutines won't be able to send. For an unbuffered channel, the send operation will block until it has been received. Therefore, the deferred wg.Done
call would never happen, and your program is deadlocked. Since Done
is only called after the forever-blocking send has been performed.
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
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论