在一段时间后运行函数,使用什么更好?

huangapple go评论92阅读模式
英文:

What is better to use for running function after some time?

问题

什么更好使用?time.AfterFunc 还是带有 sleep 的 goroutine?

time.AfterFunc(d, func() {
  // 事情
})
go func() {
  time.Sleep(d)
  // 事情
}()

这两种方法都可以实现在一定时间后执行某些操作。它们的选择取决于具体的需求和场景。

  • 如果你只需要在指定时间后执行一次操作,并且不需要取消或重置定时器,那么使用 time.AfterFunc 是一个简单且方便的选择。它会在指定的时间过后调用提供的函数。

  • 如果你需要在指定时间后执行操作,并且可能需要在执行之前取消或重置定时器,那么使用带有 sleep 的 goroutine 是更灵活的选择。你可以使用 time.Sleep 来暂停 goroutine 的执行,然后在指定的时间过后执行操作。

总的来说,如果你只需要简单地在指定时间后执行操作,而不需要取消或重置定时器,那么 time.AfterFunc 是更直观和方便的选择。如果你需要更多的灵活性和控制权,可以使用带有 sleep 的 goroutine。

英文:

What is better to use? time.AfterFunc or goroutine with sleep?

time.AfterFunc(d, func() {
  // things
})
go func() {
  time.Sleep(d)
  // things
}()

答案1

得分: 3

大多数计算机科学问题都取决于使用情况。你的两个选择都会创建一个goroutine。话虽如此,我会避免使用time.Sleep(),因为它是不可中断的。

看一个假设的轮询服务示例:

func poller(ctx context.Context) (err error) {
    for {
        if err = pollRecords(ctx); err != nil {
            return
        }
        time.Sleep(1*time.Hour) // <- 轮询间隔无法中断
    }
}

即使上下文已被取消,这个函数可能会运行长达一小时,因为time.Sleep是不可中断的。

为了修复这个问题,可以使用基于通道的time.After()

// time.Sleep(1*time.Hour)

select {
case <-ctx.Done():
    return ctx.Err() // 取消上下文会中断time.After
case <-time.After(1*time.Hour):
}

注意:time.AfterFunc可以被取消,但需要捕获返回的time.Timer

t := time.AfterFunc(d, func() {
  // 做一些事情
})

// ...

t.Stop() // 如果决定停止函数触发,可以调用该方法
英文:

Like most computer science questions - the answer depends on the usage. Both your choices will create a goroutine. Having said that, I'd avoid time.Sleep() as it's uninterruptible.

Looking at a contrived polling service example:

func poller(ctx context.Context) (err error) {
    for {
        if err = pollRecords(ctx); err != nil {
            return
        }
        time.Sleep(1*time.Hour) // &lt;- poll interval cannot be interrupted
    }
}

this function may be running for up to an hour, even after the context has been canceled, because of the uninterruptible nature of time.Sleep.

To fix, one can use the channel based time.After():

// time.Sleep(1*time.Hour)

select {
case &lt;-ctx.Done():
    return ctx.Err() // cancelling the context interrupts the time.After
case &lt;-time.After(1*time.Hour):
}

Note time.AfterFunc can be canceled - but you need to capture the returned time.TImer:

t := time.AfterFunc(d, func() {
  // things
})

// ...

t.Stop() // will stop the function firing - if one decides to do so

huangapple
  • 本文由 发表于 2021年10月13日 02:34:07
  • 转载请务必保留本文链接:https://go.coder-hub.com/69545432.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定