多通道读取错误



像许多go程序员一样,到目前为止,我一直避免使用通道做任何重要的事情,所以这个看似简单的场景让我难住了!

我想要多个例程发送由单个父程序检查的结果。如果其中任何一个发送错误,父进程应该发出信号让它们全部停止。父程序应该非顺序地读取结果。

如果其中一个程序发送错误,即如果您在nums内的11中注释,否则我们将永远陷入for循环。

func main() {
type Result struct {
Error    error
Response int
}
checkStatus := func(done <-chan interface{}, ns []int) <-chan Result {
results := make(chan Result)
go func() {
defer close(results)
for _, n := range ns {
result := Result{Response: n}
if n == 11 {
result.Error = fmt.Errorf("problem...n")
}
select {
case <-done:
return
case results <- result:
}
}
}()
return results
}
done := make(chan interface{})
defer close(done)
nums := []int{1, 2, 3, 4, 5 /*11,*/, 6, 7, 8, 9, 10}
c1 := checkStatus(done, nums[:5])
c2 := checkStatus(done, nums[5:])
for {
var r Result
select {
case r = <-c1:
if r.Error != nil {
fmt.Printf("error1: %v", r.Error)
return
}
fmt.Printf("Response1: %vn", r.Response)
case r = <-c2:
if r.Error != nil {
fmt.Printf("error2: %v", r.Error)
return
}
fmt.Printf("Response2: %vn", r.Response)
}
}
}

我能看到修复它的唯一方法是改变for循环,所以它从c1c2读取,但我看不到一种方法来做这个非顺序的?

https://go.dev/play/p/7dRPMDn1Za2

从关闭的通道读取,它们总是返回零值。您可以做的是在读取通道时使用逗号ok来关闭选择情况,然后将通道赋值为nil。如果另一个也是nil,则返回。

没有通道的case永远不会运行。

只需扩展您的代码(类似于c2的情况):

case r, ok := <-c1:
if !ok {
c1 = nil
if c2 == nil {
return
}
continue
}
if r.Error != nil {
fmt.Printf("error1: %v", r.Error)
return
}
fmt.Printf("Response1: %vn", r.Response)

但是我宁愿尝试重构整个实现。

您可以考虑使用syncpkg中的sync.WaitGrouperrgrouppkg中的errgroup.Group

相关内容

最新更新