首页 > 解决方案 > 停止 time.NewTimer 在 for 循环中初始化

问题描述

我有一个类似于以下程序的程序:

package main

import (
    "fmt"
    "time"
)

func main() {
    ch := make(chan string)
    go endProgram(ch)
    printFunc(ch)
}

func printFunc(ch chan string) {
    for {
        timeout := time.NewTimer(getTimeoutDuration())
        defer timeout.Stop()
        select {
        case s := <-ch:
            fmt.Println(s)
            return
        case <-timeout.C:
            fmt.Println("Current value")
        }
    }
}

func endProgram(ch chan string) {
    time.Sleep(time.Second * 8)
    ch <- "Exit function"
}

func getTimeoutDuration() time.Duration {
    return time.Second * 3
}

在这种情况下停止timeout计时器的最佳方法是什么?

我知道上面不是推荐的方法,因为在 for 循环中使用 defer 是一种不好的做法。另一种方法是time.After在 for 循环中使用,而不是time.NewTimer因为我们不必 stop time.After。但是如果函数在计时器触发( Sourcetime.After )之前退出,则会导致资源泄漏。

标签: loopsgotimerdeferred-execution

解决方案


如果您使用上下文而不是计时器,则仅在退出函数案例条件时才调用取消。

package main

import (
    "context"
    "fmt"
    "time"
)

func main() {
    ch := make(chan string)
    go endProgram(ch)
    printFunc(ch)
}

func printFunc(ch chan string) {
    for {
        ctx, cancel := context.WithTimeout(context.Background(), getTimeoutDuration())
        select {
        case s := <-ch:
            cancel()
            fmt.Println(s)
            return
        case <-ctx.Done():
            fmt.Println("Current value")
        }
    }
}

func endProgram(ch chan string) {
    time.Sleep(time.Second * 8)
    ch <- "Exit function"
}

func getTimeoutDuration() time.Duration {
    return time.Second * 3
}

推荐阅读