Go语言 如何获得时间,滴答滴答立即

dy2hfwbg  于 2023-02-17  发布在  Go
关注(0)|答案(7)|浏览(136)

我有一个循环,它会一直迭代,直到一个作业启动并运行:

ticker := time.NewTicker(time.Second * 2)
defer ticker.Stop()

started := time.Now()
for now := range ticker.C {
    job, err := client.Job(jobID)
    switch err.(type) {
    case DoesNotExistError:
        continue
    case InternalError:
        return err
    }

    if job.State == "running" {
        break
    }

    if now.Sub(started) > time.Minute*2 {
        return fmt.Errorf("timed out waiting for job")
    }
}

在生产中工作得很好。唯一的问题是它使我的测试变慢。它们都要等待至少2秒钟才能完成。有没有办法让time.Tick立即滴答作响?

vddsk6oq

vddsk6oq1#

不幸的是,Go语言开发者在可预见的未来不会添加这样的功能,所以我们必须科普......
有两种常用的方式使用股票代码:

for循环

假设如下:

ticker := time.NewTicker(period)
defer ticker.Stop()
for <- ticker.C {
    ...
}

用途:

ticker := time.NewTicker(period)
defer ticker.Stop()
for ; true; <- ticker.C {
    ...
}

for-select循环

假设如下:

interrupt := make(chan os.Signal, 1)
signal.Notify(interrupt, os.Interrupt)

ticker := time.NewTicker(period)
defer ticker.Stop()

loop:
for {
    select {
        case <- ticker.C: 
            f()
        case <- interrupt:
            break loop
    }
}

用途:

interrupt := make(chan os.Signal, 1)
signal.Notify(interrupt, os.Interrupt)

ticker := time.NewTicker(period)
defer ticker.Stop()

loop:
for {
    f()

    select {
        case <- ticker.C: 
            continue
        case <- interrupt:
            break loop
    }
}

为什么不直接使用time.Tick()呢?

虽然Tick对于不需要关闭Ticker的客户端很有用,但是要注意,如果没有办法关闭它,垃圾收集器就无法恢复底层的Ticker;它会“泄漏”。
https://golang.org/pkg/time/#Tick

omtl5h9j

omtl5h9j2#

ticker := time.NewTicker(period)
for ; true; <-ticker.C {
    ...
}

https://github.com/golang/go/issues/17601

6kkfgxo0

6kkfgxo03#

Ticker的实际内部实现相当复杂,但是你可以用一个goroutine来 Package 它:

func NewTicker(delay, repeat time.Duration) *time.Ticker {
    ticker := time.NewTicker(repeat)
    oc := ticker.C
    nc := make(chan time.Time, 1)
    go func() {
        nc <- time.Now()
        for tm := range oc {
            nc <- tm
        }
    }()
    ticker.C = nc
    return ticker
}
7bsow1i6

7bsow1i64#

如果你想立刻检查作业,不要在for循环中使用代码作为条件。例如:

ticker := time.NewTicker(2 * time.Second)
defer ticker.Stop()

started := time.Now()
for {
    job, err := client.Job(jobID)
    if err == InternalError {
        return err
    }

    if job.State == "running" {
        break
    }

    now := <-ticker.C
    if now.Sub(started) > 2*time.Minute {
        return fmt.Errorf("timed out waiting for job")
    }
}

如果您确实需要检查DoesNotExistError,那么您需要确保在代码显示之后进行检查,这样就不会出现忙等待的情况。

eit6fx6z

eit6fx6z5#

我编造了这样的故事

func main() {
    t := time.Now()
    callme := func() {
        // do somethign more
        fmt.Println("callme", time.Since(t))
    }
    ticker := time.NewTicker(10 * time.Second)
    first := make(chan bool, 1)
    first <- true
    for {
        select {
        case <-ticker.C:
            callme()
        case <-first:
            callme()
        }
        t = time.Now()
    }
    close(first)
}
vqlkdk9b

vqlkdk9b6#

我认为这可能是for-select循环的一个有趣的替代方案,特别是当case的内容不是一个简单的函数时:
具有:

interrupt := make(chan os.Signal, 1)
signal.Notify(interrupt, os.Interrupt)

ticker := time.NewTicker(period)
defer ticker.Stop()

loop:
for {
    select {
        case <- ticker.C: 
            f()
        case <- interrupt:
            break loop
    }
}

用途:

interrupt := make(chan os.Signal, 1)
signal.Notify(interrupt, os.Interrupt)

ticker := time.NewTicker(period)
defer ticker.Stop()
firstTick := false

// create a wrapper of the ticker that ticks the first time immediately
tickerChan := func() <-chan time.Time {
  if !firstTick {
    firstTick = true
    c := make(chan time.Time, 1)
    c <- time.Now()
    return c
  }

  return ticker.C
}

loop:
for {
    select {
        case <- tickerChan(): 
            f()
        case <- interrupt:
            break loop
    }
}
ivqmmu1c

ivqmmu1c7#

使用Timer代替Ticker怎么样?Timer可以从零持续时间开始,然后重置为所需的持续时间值:

timer := time.NewTimer(0)
defer timer.Stop()

for {
    select {
        case <-timer.C:
            timer.Reset(interval)
            job()
        case <-ctx.Done():
            break
    }
}

相关问题