2 回答

TA貢獻1811條經驗 獲得超4個贊
這似乎是不可能的,因為cancel()
它不是主 goroutine 中的阻塞操作。正因為如此,當select
解除阻塞時,可能會有多種情況可用,并且沒有辦法讓一個渠道優(yōu)于另一個渠道。任何類型的 check-channel-then-write 方案都將是活潑的,因為在檢查后可以取消上下文。
使用done
通道并寫入它而不是上下文取消將起作用,因為寫入done
通道將是主 goroutine 的阻塞操作,并且 select 將始終有一個活動案例。

TA貢獻1876條經驗 獲得超7個贊
請注意,這是一個更新的答案,因為原始答案存在問題。
正如其他人所指出的,如果沒有額外的同步,您將無法避免競爭條件。您可以使用 Mutex,但sync.Cond看起來很合適。在下面的代碼中,接收 goroutine 表示它已從 chan 接收到值。它在發(fā)出信號之前取消上下文(使用Cond.Signal),發(fā)送 goroutine 等待信號。這避免了競爭條件,因為上下文狀態(tài)在被檢查之前已更新。
ctx, cancel := context.WithCancel(context.Background())
ch := make(chan int)
cond := sync.NewCond(&sync.Mutex{}) // *** new
go func() {
defer close(ch)
cond.L.Lock() // *** new
defer cond.L.Unlock() // *** new
for i := 1; ; i++ {
ch <- i // *** moved
cond.Wait() // *** new
if ctx.Err() != nil { // *** changed
return
}
}
}()
print(<-ch)
cond.Signal() // *** new
print(<-ch)
cond.Signal() // *** new
print(<-ch)
cancel()
cond.Signal() // *** new
print(<-ch)
cond.Signal() // *** new
這是我能看到的最簡單的方法,接收 goroutine 在取消上下文后將不會在通道上接收任何值。
- 2 回答
- 0 關注
- 126 瀏覽
添加回答
舉報