<p>Hello fellow Gophers,</p>
<p>I am trying to schedule a function call to the exact start of a Minute every Minute (or at least as close as possible to the 0 Second of the Minute) and I came up with the following Go Program. There are Several things about this Program that I don't like and I would like to ask what you all think about this.</p>
<pre><code>package main
import (
"fmt"
"time"
)
func main() {
var currentTime = time.Now()
var startTime = currentTime.Truncate(time.Minute).Add(time.Minute)
fmt.Printf("Current: \t%v\nStartAt: \t%v\n", currentTime, startTime)
var duration = startTime.Sub(currentTime)
time.Sleep(duration)
var ticker = time.NewTicker(1 * time.Minute).C
var timeout = time.NewTimer(5 * time.Minute).C
loop:
for {
select {
case tick := <-ticker:
fmt.Printf("Tick: \t\t%v\n", tick)
case <-timeout:
break loop
}
}
fmt.Printf("EndTime: \t%v\n", time.Now())
}
</code></pre>
<p>Output of the Program:</p>
<pre><code>Current: 2016-02-09 00:03:19.45209065 +0100 CET
StartAt: 2016-02-09 00:04:00 +0100 CET
Tick: 2016-02-09 00:05:00.000363957 +0100 CET
Tick: 2016-02-09 00:06:00.000370028 +0100 CET
Tick: 2016-02-09 00:07:00.000368027 +0100 CET
Tick: 2016-02-09 00:08:00.000387177 +0100 CET
Tick: 2016-02-09 00:09:00.00037631 +0100 CET
EndTime: 2016-02-09 00:09:00.000421761 +0100 CET
</code></pre>
<p>One of the things I don't like is that the time to the First Tick from the start of the Program can be up to 2 Minutes. If the Ticker would release a Tick immediately then it would cut that Time down to only 1 Minute. I could, of course, Repeat the function Call in front of the loop which would also cut down that time to around 1 minute, but I just don't like to repeat myself in code and would like to avoid it if there is a better way.</p>
<p>I also don't like that I have to rely on time.Sleep(duration) to set the start time of the Ticker and the Timer. Is there a way to start the Ticker explicitly? If that is possible I could then replace the time.Sleep with a time.After and a additional case in the Select which would then Start the Ticker and Timer.</p>
<p>What do you think? Is this a good way of doing this? Are there ways to make this code a bit nicer? </p>
<p>Thank you in advance. </p>
<hr/>**评论:**<br/><br/>motojo: <pre><p>EDIT: Ignore this code, look at the subcomments.</p>
<p>Here is what I do in my programs when I want to run on the minute:</p>
<pre><code>func minuteTicker() *time.Ticker {
// Current time
now := time.Now()
// Get the number of seconds until the next minute
var d time.Duration
d = time.Second * time.Duration(60-now.Second())
// Time of the next tick
nextTick := now.Add(d)
// Subtract next tick from now
diff := nextTick.Sub(time.Now())
// Return new ticker
return time.NewTicker(diff)
}
</code></pre></pre>Nooby1990: <pre><p>I am not sure I understand this correctly.</p>
<p>Wouldn't diff just be equal to d since you are adding d to now and then subtract now again? Or at least almost equal since some fractions of a second have passed between the 2 time.Now calls. Couldn't you just skip the adding and subtracting and get the same result?</p>
<p>And since d is basically a random duration only the first Tick would be exactly on the Minute and the following Ticks would be timed for the random duration d. I would then need to start a Ticker for the Minute intervals on the First tick of this ticker. Which is basically what I am doing above with <code>time.Sleep(duration)</code>.</p></pre>motojo: <pre><p>You're right, some code could be skipped. I shortened it.</p>
<p>Here is the code so you can test: <a href="https://gist.github.com/josephspurrier/ec57821bc4a3442a74ca" rel="nofollow">https://gist.github.com/josephspurrier/ec57821bc4a3442a74ca</a></p>
<pre><code>2016/02/09 18:41:17 Started ticker
2016/02/09 18:42:00 Tick
2016/02/09 18:43:00 Tick
</code></pre></pre>zihua: <pre><p>How about something simple like this?
<a href="http://play.golang.org/p/mDYvMTcZjR" rel="nofollow">http://play.golang.org/p/mDYvMTcZjR</a></p></pre>Fwippy: <pre><p>Why do you need it to run at the very beginning of the minute?</p>
<p>You can just manually run your first tick; put a <code>ticker <- time.Now()</code> right after you create your ticker.</p></pre>Nooby1990: <pre><p>I guess it does not have to be the start of a minute, but with the systems I am dealing with I would like to define the times and Intervals at least to the specific seconds. If I can schedule a call every Minute at the start of the Minute, then I can also easily schedule other times and Intervals which would help immensely.</p>
<p>Sending a Time down the Chanel of the Ticker does seem like a clever solution, but unfortunately I can not send something to the chanel. I can only Receive from it.</p>
<pre><code>invalid operation: ticker <- time.Now() (send to receive-only type <-chan time.Time)
</code></pre>
<p>The Documentation defines the Ticker Chanel like this:</p>
<pre><code>C <-chan Time
</code></pre>
<p>But thank you for this Idea. I would not have thought about just sending something to the Chanel.</p></pre>Fwippy: <pre><p>Ah; sorry about that! I didn't notice it was receive-only from the spec. You can probably abstract it out to a simple function, and then call that in addition.</p></pre>010a: <pre><p>I can't think of any cleaner ways. Its a strange problem, and thus is likely to have a strange solution. </p></pre>Nooby1990: <pre><p>Is it really such a strange thing to do? It does not seem that strange to me. I guess people usually use cron or similar solve something like this. Which, unfortunately, I don't think I can to with this Project.</p></pre>Consuelas-Revenge: <pre><p>Another approach is to just implement your own ticker <a href="https://play.golang.org/p/3VL2_jK46j" rel="nofollow">https://play.golang.org/p/3VL2_jK46j</a></p>
<p>It can even be simplified by getting rid of the channels and just call the target code directly.</p></pre>Nooby1990: <pre><p>Implementing my own Ticker is probably the cleanest and nicest solution. Thank you for the suggestion.</p>
<p>I don't think that I want to get rid of the channels since I would need to have tickers for multiple use cases. Or I could get rid of the channels and make a ticker that gets a function as an argument and call that function on every tick. I don't know yet, I am going to play around with this some more and try out which is better for me.</p>
<p>But I am certain that you just set me in the right direction. Thank you.</p></pre>
这是一个分享于 的资源,其中的信息可能已经有所发展或是发生改变。
入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889
- 请尽量让自己的回复能够对别人有帮助
- 支持 Markdown 格式, **粗体**、~~删除线~~、
`单行代码`
- 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
- 图片支持拖拽、截图粘贴等方式上传