]> Cypherpunks repositories - gostls13.git/commitdiff
time: add Ticker.Reset
authorChangkun Ou <hi@changkun.us>
Mon, 3 Feb 2020 13:42:32 +0000 (14:42 +0100)
committerIan Lance Taylor <iant@golang.org>
Sun, 23 Feb 2020 16:09:02 +0000 (16:09 +0000)
This CL implements Ticker.Reset method in time package.

Benchmark:
name                 time/op
TickerReset-12       6.41µs ±10%
TickerResetNaive-12  95.7µs ±12%

Fixes #33184

Change-Id: I12c651f81e452541bcbbc748b45f038aae1f8dae
Reviewed-on: https://go-review.googlesource.com/c/go/+/217362
Run-TryBot: Ian Lance Taylor <iant@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
api/next.txt
doc/go1.15.html
src/runtime/time.go
src/time/sleep.go
src/time/tick.go
src/time/tick_test.go

index ecc3c4f0b69cbeb0322d114eda8ca3d41d3cfce3..cab86a9904184fdb4b022bbbbe627ee8b8ce13f3 100644 (file)
@@ -1 +1,2 @@
 pkg testing, method (*T) Deadline() (time.Time, bool)
+pkg time, method (*Ticker) Reset(Duration)
index a3a089e07e664aee05b2bf84288556f90987b0b9..ed240d85ccae33925ff421976db0ac7f2da7ab3f 100644 (file)
@@ -80,3 +80,13 @@ TODO
 <p>
 TODO
 </p>
+
+<dl id="time"><dt><a href="/pkg/time/">time</a></dt>
+  <dd>
+    <p><!-- golang.org/issue/33184 -->
+       The new method
+       <a href="/pkg/time#Ticker.Reset"><code>Ticker.Reset</code></a>
+       supports changing the duration of a ticker.
+    </p>
+  </dd>
+</dl><!-- time -->
index af5db4cc58b761c17f1d641be422bf9daf7a3047..9e1129537a7ac1329faf0041ce7af1ef9430878c 100644 (file)
@@ -233,6 +233,12 @@ func resetTimer(t *timer, when int64) {
        resettimer(t, when)
 }
 
+// modTimer modifies an existing timer.
+//go:linkname modTimer time.modTimer
+func modTimer(t *timer, when, period int64, f func(interface{}, uintptr), arg interface{}, seq uintptr) {
+       modtimer(t, when, period, f, arg, seq)
+}
+
 // Go runtime.
 
 // Ready the goroutine arg.
@@ -402,7 +408,7 @@ func dodeltimer0(pp *p) bool {
 }
 
 // modtimer modifies an existing timer.
-// This is called by the netpoll code.
+// This is called by the netpoll code or time.Ticker.Reset.
 func modtimer(t *timer, when, period int64, f func(interface{}, uintptr), arg interface{}, seq uintptr) {
        if when < 0 {
                when = maxWhen
index 37de846b114a88194e4beec43d80497b1391cdd2..bd0ed9aaba88acbc948cce31d908f89e8f7dba4c 100644 (file)
@@ -39,6 +39,7 @@ func when(d Duration) int64 {
 func startTimer(*runtimeTimer)
 func stopTimer(*runtimeTimer) bool
 func resetTimer(*runtimeTimer, int64)
+func modTimer(t *runtimeTimer, when, period int64, f func(interface{}, uintptr), arg interface{}, seq uintptr)
 
 // The Timer type represents a single event.
 // When the Timer expires, the current time will be sent on C,
index e4cd43aa82aef5b6ec2de6542bbf5dfbd122bd25..152d5a706be4e0daba0404de4058706f803a6bd1 100644 (file)
@@ -46,6 +46,15 @@ func (t *Ticker) Stop() {
        stopTimer(&t.r)
 }
 
+// Reset stops a ticker and resets its period to the specified duration.
+// The next tick will arrive after the new period elapses.
+func (t *Ticker) Reset(d Duration) {
+       if t.r.f == nil {
+               panic("time: Reset called on uninitialized Ticker")
+       }
+       modTimer(&t.r, when(d), int64(d), t.r.f, t.r.arg, t.r.seq)
+}
+
 // Tick is a convenience wrapper for NewTicker providing access to the ticking
 // channel only. While Tick is useful for clients that have no need to shut down
 // the Ticker, be aware that without a way to shut it down the underlying
index 71ea3672b86645a4d8d35e9be033f39930d468a8..d05b345efb6110a6527903a2810d9506761eab44 100644 (file)
@@ -36,13 +36,17 @@ func TestTicker(t *testing.T) {
        for i := 0; i < 5; i++ {
                ticker := NewTicker(delta)
                t0 := Now()
-               for i := 0; i < count; i++ {
+               for i := 0; i < count/2; i++ {
+                       <-ticker.C
+               }
+               ticker.Reset(delta * 2)
+               for i := count / 2; i < count; i++ {
                        <-ticker.C
                }
                ticker.Stop()
                t1 := Now()
                dt := t1.Sub(t0)
-               target := delta * Duration(count)
+               target := 3 * delta * Duration(count/2)
                slop := target * 2 / 10
                if dt < target-slop || dt > target+slop {
                        errs = append(errs, fmt.Sprintf("%d %s ticks took %s, expected [%s,%s]", count, delta, dt, target-slop, target+slop))
@@ -118,3 +122,24 @@ func BenchmarkTicker(b *testing.B) {
                ticker.Stop()
        })
 }
+
+func BenchmarkTickerReset(b *testing.B) {
+       benchmark(b, func(n int) {
+               ticker := NewTicker(Nanosecond)
+               for i := 0; i < n; i++ {
+                       ticker.Reset(Nanosecond * 2)
+               }
+               ticker.Stop()
+       })
+}
+
+func BenchmarkTickerResetNaive(b *testing.B) {
+       benchmark(b, func(n int) {
+               ticker := NewTicker(Nanosecond)
+               for i := 0; i < n; i++ {
+                       ticker.Stop()
+                       ticker = NewTicker(Nanosecond * 2)
+               }
+               ticker.Stop()
+       })
+}