var timer *time.Timer
func A() {
timer.Stop() // cancel old timer
go B() // new timer
}
func B() {
timer = time.NewTimer(100 * time.Millisecond)
select {
case <- timer.C:
// do something for timeout, like change state
}
}
函数 A 和 B 都在不同的 goroutine 中。
假设 A 在一个 RPC 协程中。当应用程序收到 RPC 请求时,它会取消 B 中的旧计时器,并在另一个 goroutine 中启动一个新计时器。
医生说:
Stop does not close the channel, to prevent a read from the channel succeeding incorrectly.
那么如何打破 B 中的选择以避免 goroutine 泄漏?
最佳答案
使用额外的、独立的抵消信号。由于您已经有一个 select 语句,另一个 channel 是显而易见的选择:
import "time"
var timer *time.Timer
var canceled = make(chan struct{})
func A() {
// cancel all current Bs
select {
case canceled <- struct{}{}:
default:
}
timer.Stop()
go B() // new timer
}
func B() {
timer = time.NewTimer(100 * time.Millisecond)
select {
case <-timer.C:
// do something for timeout, like change state
case <-canceled:
// timer aborted
}
}
请注意,所有 A 和 B 都在为定时器值相互竞争。使用上面的代码,没有必要让 A 停止计时器,因此您不需要全局计时器,从而消除了竞争:
import "time"
var canceled = make(chan struct{})
func A() {
// cancel all current Bs
select {
case canceled <- struct{}{}:
default:
}
go B()
}
func B() {
select {
case <-time.After(100 * time.Millisecond):
// do something for timeout, like change state
case <-canceled:
// aborted
}
}
关于go - 如何正确停止定时器?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50223771/