我在GO中有一个简单的并发用例,但是我想不出一个优雅的解决方案来解决我的问题.
我想要编写一个方法fetchAll
,该方法并行地从远程服务器查询未指定数量的资源.如果任何获取失败,我希望立即返回第一个错误.
我最初的实现泄露了Goroutines:
package main
import (
"fmt"
"math/rand"
"sync"
"time"
)
func fetchAll() error {
wg := sync.WaitGroup{}
errs := make(chan error)
leaks := make(map[int]struct{})
defer fmt.Println("these goroutines leaked:", leaks)
// run all the http requests in parallel
for i := 0; i < 4; i++ {
leaks[i] = struct{}{}
wg.Add(1)
go func(i int) {
defer wg.Done()
defer delete(leaks, i)
// pretend this does an http request and returns an error
time.Sleep(time.Duration(rand.Intn(100)) * time.Millisecond)
errs <- fmt.Errorf("goroutine %d's error returned", i)
}(i)
}
// wait until all the fetches are done and close the error
// channel so the loop below terminates
go func() {
wg.Wait()
close(errs)
}()
// return the first error
for err := range errs {
if err != nil {
return err
}
}
return nil
}
func main() {
fmt.Println(fetchAll())
}
操场:https://play.golang.org/p/Be93J514R5个
从阅读https://blog.golang.org/pipelines中我知道我可以创建一个信号通道来清理其他线程.或者,我可以使用context
来完成它.但是看起来这么简单的用例应该有一个我没有的更简单的解决方案.