如何获取时间。

I have a loop that iterates until a job is up and running:

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")
    }
}

Works great in production. The only problem is that it makes my tests slow. They all wait at least 2 seconds before completing. Is there anyway to get time.Tick to tick immediately?

The actual implementation of Ticker internally is pretty complicated. But you can wrap it with a goroutine:

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
}

If you want to check the job right away, don't use the ticker as the condition in the for loop. For example:

ticker := time.NewTicker(time.Second * 2)
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")
    }
}

If you do still need to check for DoesNotExistError, you want to make sure you do it after the ticker so you don't have a busy-wait.

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

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

Unfortunately, it seems that Go developers will not add such functionality in any foreseeable future, so we have to cope...

There are two common ways to use tickers:

for loop

Given something like this:

for <- time.Tick(period) {
    ...
}

Use:


for ; true; <- time.Tick(period) {
    ...
}

for-select loop

Given something like this:

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

loop:
for {
    select {
        case <- time.Tick(period): 
            f()
        case <- interrupt:
            break loop
    }
}

Use:

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

loop:
for {
    f()

    select {
        case <- time.Tick(period): 
            continue
        case <- interrupt:
            break loop
    }
}