英文:
Defer close on multiple Goroutines?
问题
我有以下代码:
package main
import (
"fmt"
"time"
)
func main() {
t := time.Now()
stuff := fanIn(
generator(4, 5, 6, 7),
generator(1, 2, 6, 3, 7),
generator(12, 15, 33, 40, 10),
generator(18, 13, 20, 40, 15),
generator(100, 200, 64000, 3121, 1237),
)
for v := range stuff {
fmt.Println(v)
}
fmt.Println(t.Sub(time.Now()))
}
func generator(nums ...int) <-chan int {
out := make(chan int, 10)
go func() {
defer close(out)
for _, v := range nums {
out <- v
}
}()
return out
}
func fanIn(in ...<-chan int) <-chan int {
out := make(chan int, 10)
for _, v := range in {
go func(ch <-chan int) {
for val := range ch {
go func(c int) { out <- c }(val)
}
}(v)
}
return out
}
在第18行出现了死锁:
for v := range stuff {...}
问题(我认为)是我没有在返回只读通道的fanIn函数上延迟关闭。我不知道何时延迟关闭,因为它必须等待多个goroutine完成。
解决这个死锁的惯用方法是什么?这段代码是否符合惯用方式?
谢谢!
英文:
I have the following code:
package main
import (
"fmt"
"time"
)
func main() {
t := time.Now()
stuff := fanIn(
generator(4, 5, 6, 7),
generator(1, 2, 6, 3, 7),
generator(12, 15, 33, 40, 10),
generator(18, 13, 20, 40, 15),
generator(100, 200, 64000, 3121, 1237),
)
for v := range stuff {
fmt.Println(v)
}
fmt.Println(t.Sub(time.Now()))
}
func generator(nums ...int) <-chan int {
out := make(chan int, 10)
go func() {
defer close(out)
for _, v := range nums {
out <- v
}
}()
return out
}
func fanIn(in ...<-chan int) <-chan int {
out := make(chan int, 10)
for _, v := range in {
go func(ch <-chan int) {
for val := range ch {
go func(c int) { out <- c }(val)
}
}(v)
}
return out
}
It results in a deadlock on line 18:
for v := range stuff {...}
The issue (I think) is that I'm not deferring the close on the fanIn function that returns a read-only channel. I don't know when to defer it since it's got to wait for the end of multiple goroutines to complete.
What's the idiomatic way to solve this deadlock? Is this code even idiomatic?
Thanks!
答案1
得分: 4
你对错误原因的判断是正确的,即未关闭fanIn
的通道。你可以使用sync.WaitGroup
来解决这个问题:
func fanIn(in ...<-chan int) <-chan int {
// 在这里使用一个 WaitGroup
var wg sync.WaitGroup
out := make(chan int, 10)
for _, v := range in {
wg.Add(1)
go func(ch <-chan int) {
defer wg.Done()
for val := range ch {
out <- val
}
}(v)
}
// 在另一个 goroutine 中等待 WaitGroup 完成
go func() {
wg.Wait()
close(out)
}()
return out
}
[可工作的代码][2]。
[1]: https://golang.org/pkg/sync/#WaitGroup
[2]: https://play.golang.org/p/sWxVay-KWP
请注意,我只翻译了代码部分,其他内容不包括在内。
英文:
You are correct about the cause of error being un-closed fanIn
's channel. You can use a sync.WaitGroup
to resolve the issue:
func fanIn(in ...<-chan int) <-chan int {
// use a WaitGroup here
var wg sync.WaitGroup
out := make(chan int, 10)
for _, v := range in {
wg.Add(1)
go func(ch <-chan int) {
defer wg.Done()
for val := range ch {
out <- val
}
}(v)
}
// wait for wait groups to finish in another goroutine
go func() {
wg.Wait()
close(out)
}()
return out
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论