go - 如何正确停止定时器?

标签 go goroutine

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/

相关文章:

parallel-processing - goroutines 在多核处理器上的表现如何

go - 使用互斥锁 - 仍然是死锁

go - 关于golang channel 的一些问题

sockets - 去吧,tcp打开文件太多调试

java - 无法验证在 Go 中创建的 Java 中的 DSA 签名,反之亦然

go - 如何告诉我的 go build 在 vendor 文件夹中查找 godep 库?

multithreading - 为什么这个程序在分配的线程越少时运行得越快?

go - 即使关闭, channel 也不会消亡

go - go中的非阻塞 channel

Golang多维 slice 复制