我在创建几个goroutine时遇到了一个问题,使用sync.WaitGroup
在适当的时候将所有内容组合在一起。
基本上,我尝试过写这样的东西:
//global var
var wg sync.WaitGroup
//say inside main:
ch1 := make(chan *MyStruct) // data we're after
ch2 := make(chan string) // only used for warnings
result := []*MyStruct{}
for p := range data {
wg.Add(1)
go processData(p, ch1, ch2)
}
wg.Wait()
close(ch1)
close(ch2)
for elem := range(ch1) {
result = append(result, elem)
}
for warn := range(ch2) {
log.Printf("%s" warn)
}
goroutine函数看起来像这样:
//processData
func processData(p interface{}, ch1 chan *MyStruct, ch2 chan string) {
defer wg.Done()
data := &MyStruct{}
data.raw = p
//based on certain conditions, this can happen:
if data.NeedsMoreProcessing() {
wg.Add(1)
go additionalProcessing(data, ch2)
}
ch1 <- data
}
func additionalProcessing(data *MyStruct, ch chan<- string) {
defer wg.Done()
if err := data.ExtraStuff(); err != nil {
ch <- fmt.Sprintf(
"Additional processing on element %d failed: %s",
data.Id,
err.Error(),
)
return
}
data.SetAdditionalInfo()
}
AFAIK,我正确地调用wg.Add
(在goroutine开始之前),我知道例程需要一段时间(他们使用http.get
调用等...)。我没有得到常见的&#34;致命错误:所有goroutines都睡着了 - 死锁!&#34; 错误消息。
相反,Wait
来电似乎永远不会回来。当我将该调用包装在它自己的例程中时,问题得到了解决:
go func() {
wg.Wait()
close(ch1)
close(ch2)
}()
但除此之外,一切都保持原样。为什么这样,似乎我们需要在goroutine中调用Wait
?在这种情况下,我真的没有看到太大的区别。在我的特定情况下,例程需要几秒钟才能完成,在Wait
调用之前确定没有完成例程的风险吗?