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 關注
- 106 瀏覽
添加回答
舉報