1 回答

TA贡献1934条经验 获得超2个赞
在 Golang 中,通道类似于 bash ( |) 中的管道。但与用于将一个命令的输出传输到另一个命令的输入的 bash 管道不同,Go 通道用于在 goroutine 之间传输一些数据。您可以在此处阅读有关频道的更多信息。渠道有容量。当您没有为通道指定容量时,go 假定它的容量为 0。容量为零的信道通常称为unbuffered信道,而容量非零的信道称为buffered。当通道已满(通道中的元素数等于通道的容量)时,通道上的所有写操作 ( ->errs) 都会阻塞执行流程,直到<-errs出现读操作 ( ) 。
在您的特定示例中,您有无缓冲通道(容量为 0 的通道)。因此,您通道上的任何写入操作 ( ->errs) 都将阻止执行,直到提供某些读取操作为止,因此您启动的所有 goroutine 都将被阻止,尽管只有一个 goroutine 能够在函数流移动时继续进行写入main操作转发读取操作 ( err = <-errs)。
要解决您的问题,您可以创建一个额外的 goroutine,该 goroutine 会同时从通道读取数据,同时 goroutines 会写入通道。它看起来像这样:
func init() {
rand.Seed(1500929006430687579)
}
func goroutine(n int, wg *sync.WaitGroup, ch chan error) {
defer fmt.Println("defer done")
defer wg.Done()
fmt.Println("num ", n)
if n == 1 {
ch <- fmt.Errorf("error")
}
}
func main() {
var wg sync.WaitGroup
errs := make(chan error)
platforms := 2
types := 3
go func() {
for e := range errs {
fmt.Println(e)
}
}()
for j := 0; j < platforms; j++ {
for k := 0; k < types; k++ {
wg.Add(1)
n := rand.Intn(2)
go goroutine(n, &wg, errs)
}
for k := 0; k < types; k++ {
wg.Add(1)
n := rand.Intn(2)
go goroutine(n, &wg, errs)
}
}
wg.Wait()
}
此外,我在您的代码中重构了一些错误和不准确之处:
你不应该在有错误的频道中写 nil 。如果你希望
errs
chan 只包含错误,那么只有当你的函数执行时出现非零错误时才写在那里。您有一个额外的 wd.Add(1) 作为循环的开始,因此函数和函数
j
之间存在不平衡。3.Add
Done
此外,您添加
defer fmt.Println("defer done")
afterdefer wg.Done()
butdefer
s 构造的执行顺序与指定的顺序相反,因此放在defer fmt.Println("defer done")
before 之前会更正确defer wg.Done()
,这样“延迟完成”将真正表明所有先前的defer
s 已被执行。
- 1 回答
- 0 关注
- 113 浏览
添加回答
举报