1 回答
TA贡献1842条经验 获得超21个赞
问题源于这样一个事实,即当您的监控 goroutine “取出”(接收)一个值(一个函数)并执行它(这也发生在监控 goroutine 上)时,它在执行过程中会在受监控的通道上发送一个值。
这本身不会导致死锁,因为函数执行时( a()),它已经从缓冲通道中取出,因此其中至少有一个空闲空间,因此在通道内部发送新值a()可以继续进行而不会阻塞.
如果还有其他 goroutines 也可能在受监控的通道上发送值,则可能会出现问题,这就是您的情况。
避免死锁的一种方法是,如果正在执行的函数试图“放回”(发送)一个不在同一个 goroutine(即监视器 goroutine)中的函数,而是在一个新的 goroutine 中,那么监视器 goroutine 不会被阻塞:
actions <- func() {
// Send new func value in a new goroutine:
// this will never block the monitor goroutine
go func() {
actions <- func() {
// No deadlock.
}
}()
}
通过这样做,即使缓冲区actions已满,monitor goroutine 也不会被阻塞,因为在它上面发送一个值将发生在一个新的 goroutine 中(可能会被阻塞,直到缓冲区中有可用空间)。
如果你想避免在发送一个值时总是产生一个新的 goroutine actions,你可以使用 aselect来首先尝试发送它而不产生一个新的 goroutine。仅当缓冲区actions已满且无法在不阻塞的情况下发送时,您才应生成用于发送的 goroutine 以避免死锁,这取决于您的实际情况可能很少发生,在这种情况下无论如何避免死锁是不可避免的:
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
}()
}
}
如果很多地方都需要这样做,建议为其创建一个辅助函数:
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 关注
- 137 浏览
添加回答
举报