1 回答

TA貢獻(xiàn)1842條經(jīng)驗(yàn) 獲得超22個贊
問題源于這樣一個事實(shí),即當(dāng)您的監(jiān)控 goroutine “取出”(接收)一個值(一個函數(shù))并執(zhí)行它(這也發(fā)生在監(jiān)控 goroutine 上)時,它在執(zhí)行過程中會在受監(jiān)控的通道上發(fā)送一個值。
這本身不會導(dǎo)致死鎖,因?yàn)楹瘮?shù)執(zhí)行時( a()),它已經(jīng)從緩沖通道中取出,因此其中至少有一個空閑空間,因此在通道內(nèi)部發(fā)送新值a()可以繼續(xù)進(jìn)行而不會阻塞.
如果還有其他 goroutines 也可能在受監(jiān)控的通道上發(fā)送值,則可能會出現(xiàn)問題,這就是您的情況。
避免死鎖的一種方法是,如果正在執(zhí)行的函數(shù)試圖“放回”(發(fā)送)一個不在同一個 goroutine(即監(jiān)視器 goroutine)中的函數(shù),而是在一個新的 goroutine 中,那么監(jiān)視器 goroutine 不會被阻塞:
actions <- func() {
// Send new func value in a new goroutine:
// this will never block the monitor goroutine
go func() {
actions <- func() {
// No deadlock.
}
}()
}
通過這樣做,即使緩沖區(qū)actions已滿,monitor goroutine 也不會被阻塞,因?yàn)樵谒厦姘l(fā)送一個值將發(fā)生在一個新的 goroutine 中(可能會被阻塞,直到緩沖區(qū)中有可用空間)。
如果你想避免在發(fā)送一個值時總是產(chǎn)生一個新的 goroutine actions,你可以使用 aselect來首先嘗試發(fā)送它而不產(chǎn)生一個新的 goroutine。僅當(dāng)緩沖區(qū)actions已滿且無法在不阻塞的情況下發(fā)送時,您才應(yīng)生成用于發(fā)送的 goroutine 以避免死鎖,這取決于您的實(shí)際情況可能很少發(fā)生,在這種情況下無論如何避免死鎖是不可避免的:
actions <- func() {
newfv := func() { /* do something */ }
// First try to send with select:
select {
case actions <- newfv:
// Success!
default:
// Buffer is full, must do it in new goroutine:
go func() {
actions <- newfv
}()
}
}
如果很多地方都需要這樣做,建議為其創(chuàng)建一個輔助函數(shù):
func safeSend(fv func()) {
// First try to send with select:
select {
case actions <- fv:
// Success!
default:
// Buffer is full, must do it in new goroutine:
go func() {
actions <- fv
}()
}
}
并使用它:
actions <- func() {
safeSend(func() {
// something to do
})
}
- 1 回答
- 0 關(guān)注
- 160 瀏覽
添加回答
舉報