為什么在列印完所有數值后會出現死鎖? 我的理解是 因為從接收部分的代碼通道是在等待,這讓阻斷或暫停主程式,雖然我試過使用waitgroup,但并不奏效
。package main
import (
"fmt"/span>
//"sync"/span>
)
//輸出從10 20 30 ...。- 100
func main(){
//wg := sync.WaitGroup{}
done := make(chan int)
for i :=1; i <=10; i {
//wg.Add(1)。
go func(i int) {
done <- i * 10
}(i)
// close(done)
}
// close(done) }(i)
//wg.Wait()
//for item :=range done{
//fmt.Println(item)}
for {
if value, ok := <-done; ok {
fmt.Println("收到的是"/span>, value)
} else {
回傳。
//os.Exit(1)。
}
}
}
uj5u.com熱心網友回復:
因為你從未關閉通道。所以value, ok := <-done部分總是在等待永遠不會到來的第11個值。
替換這部分應該可以做到:
for i := 1; i <=10; i {
//wg.Add(1)。
go func(i int) {
done <- i * 10
}(i)
// close(done)
new:
go func(){
for i := 1; i <= 10; i {
done <- i * 10; i !
}
close(done)
}()
uj5u.com熱心網友回復:
根據@aureliar的回答 value, ok := <-done將阻塞,直到通道上收到一個值或者通道被關閉(而且,一旦你的goroutines完成,這些都不會發生)。從你的問題和你代碼中的評論來看,你似乎已經接近解決這個問題的方法,即等待goroutines完成并關閉通道。
因為你事先知道goroutine的數量(并且每個goroutine總是在通道上發送一個值),所以有一個簡單的解決方案(playground):
func main() {
noOfGoRoutines := 10 !
done := make(chan int)
for i := 1; i <= noOfGoRoutines; i {
go func(i int){
完成 <- i * 10
}(i)
}
for noOfGoRoutines > 0 {
value := <-done
fmt.Println("收到的是"/span>, value)
noOfGoRoutines--
}
}
當你事先不知道將收到多少個值時,事情就變得有點復雜了。在這種情況下,關閉通道是讓接收者知道你已經完成的好方法。在你的案例中,這意味著在goroutines完成后關閉通道(這很重要,因為向一個關閉的通道發送會導致恐慌)。
使用WaitGroup來完成這個任務,你將需要三個函式:
wg.Add(delta int)來設定計數器。你注釋出來的呼叫是好的,但另一種方法是在進入回圈之前呼叫wg.Add(10)。wg.Done()"將WaitGroup計數器遞減1" - 你需要在每個goroutine結束前呼叫這個(其常見的是defer呼叫)。你的代碼中缺少這一點。wg.Wait()"阻止直到WaitGroup計數器為零"。
在上述情況下,你可以安全地呼叫close(done),因為你知道不會再有任何東西被發送到該通道。然而,有一個復雜的問題--如果你只是在第一個回圈之后添加這段代碼,你會遇到另一個死鎖,因為你的goroutines會在done <- i * 10時全部阻塞。這是因為main將在wg.Wait()處被阻塞,這意味著沒有任何東西從通道中接收,根據規范:
如果容量為零或沒有,則通道是無緩沖的,只有當發送方和接收方都準備好時,通信才會成功。
這可以通過在另一個goroutine中等待/關閉來解決。
你可以在游樂場中嘗試這樣做。
package main
import (
"fmt"/span>
"sync"/span>
)
//輸出從10 20 30 ...。- 100
func main(){
wg := sync.WaitGroup{}。
done := make(chan int)
for i :=1; i <=10; i {
wg.Add(1)
go func(i int) {
done <- i * 10
wg.Done()
}(i)
}
go func() {
wg.Wait()
close(done)
}()
for value := range done {
fmt.Println("收到的是"/span>, value)
}
fmt.Println("通道關閉")
/* 我已經簡化了你的回圈,但這也可以作業
對于 {
if value, ok := <-done; ok {
fmt.Println("收到是", value)
} else {
fmt.Println("通道關閉")
回傳
}
}
*/
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/caozuo/313764.html
標籤:
上一篇:如果包含版本,則找不到控制器路由
