Go: time: create ticker with instant first tick

Created on 26 Oct 2016  路  13Comments  路  Source: golang/go

The current time.NewTicker(time.Duration) makes its first tick after the given duration. ue to the nature of most ticker-dependent implementations, it is hard to elegantly add a tick right after calling the method.

Therefore, I want to propose a new method time.NewTickerStart(time.Duration), f.e. that does exactly the same as time.NewTicker, but fires the first tick directly after creation.

NeedsDecision

Most helpful comment

Try:

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

All 13 comments

I note that you can write this yourself easily enough.

func NewTickerStart(d time.Duration) *time.Ticker {
    t := time.NewTicker(d)
    t.C <- time.Now()
    return t
}

I agree that this can be useful. I wonder if there is a way to find out how often people would want it. I couldn't find any cases in the standard library.

@ianlancetaylor t.C is a <-chan Time, you cannot send on that.

@ianlancetaylor @dominikh Yeah, I noticed that. So you would have to copy the section of code underneath the first <-t.C, which is not really elegant.

This doesn't seem to rise to the level of new API. You don't have to "copy the section of code underneath the first <-t.C", you just have to put the code in its own function and call that function once at the start and once after each timeout interval. That seems clear enough.

this isn't as convenient as having ticker modified because often there's extra logic surrounding handling ticket event (e.g. other cases in select {}). in this case just calling function that ticker should issue requires even more duplication

you don't need new api, just allow to send events to ticker channel

The ticker has a field:

    C <-chan Time // The channel on which the ticks are delivered.

We can't "just allow to send events to ticker channel". That can't be changed now. (And it's debatable whether we'd do it anyway, but we can't.)

Try:

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

How about select statements? Oftentimes I have to wait until some condition holds, or a context expires... and I'd like to avoid waiting for the first tick to happen.

for {
    select {
    case <-t.C:
        fmt.Println("Do work")
    case <-ctx.Done():
        fmt.Println("Done")
        return
    }
}

https://play.golang.org/p/-bXig8w-SN

@matteomiraz, as rsc suggested earlier:

f := func() {
    fmt.Println("Do work")
}

f()
for {
    select {
    case <-t.C:
        f()
    case <-ctx.Done():
            fmt.Println("Done")
        return
    }
}

That won't check if the context is valid before running the function. The correct solution is something like:

select {
case <-ctx.Done():
    return
default:
    doWork()
}
for {
    select {
    case <-t.C:
        doWork()
    case <-ctx.Done():
        return
    }
}

https://play.golang.org/p/Xl3UGqV0X5

seems quite elaborate for such a a simple use case, no?

If the timer ticks immediately and ctx is already canceled, there is no guarantee that the t.C case will not run (the select is pseudo-random). If that's what you want you need the extra select anyway.

I facing the same problem for the first tick. I would suggest Golang developer to provide this feature.

@rishiloyola this issue was closed on the 13th of June. Please do not comment on closed issues. I am locking this conversation to prevent further comment here. If you want to continue the discussion please consider opening a new issue, or see https://golang.org/wiki/Questions for good places to discuss Go. Thanks.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

bradfitz picture bradfitz  路  3Comments

rakyll picture rakyll  路  3Comments

ajstarks picture ajstarks  路  3Comments

natefinch picture natefinch  路  3Comments

gopherbot picture gopherbot  路  3Comments