From 193150b5230c7061bf10e7d3aed5dabb4f43712e Mon Sep 17 00:00:00 2001 From: Baron Schwartz Date: Thu, 23 Jan 2014 20:41:01 -0500 Subject: [PATCH 1/2] Remove Sample() until after a decision on #9 --- multitick.go | 61 +++++++---------------------------------------- multitick_test.go | 57 ------------------------------------------- 2 files changed, 8 insertions(+), 110 deletions(-) diff --git a/multitick.go b/multitick.go index cb86baa..61fb9fa 100644 --- a/multitick.go +++ b/multitick.go @@ -6,19 +6,15 @@ package multitick // Please see the LICENSE file for applicable license terms. import ( - "math/rand" "sync" "time" ) // Ticker is a broadcaster for time.Time tick events. type Ticker struct { - mux sync.Mutex // Protects chans slice and sampleFactor - chans []chan time.Time - baseInterval time.Duration - sampleFactor int - seed int64 - randGenerator *rand.Rand + mux sync.Mutex // Protects chans slice + chans []chan time.Time + baseInterval time.Duration tickerMux sync.Mutex // Used to sync start/stop ticker *time.Ticker @@ -34,8 +30,6 @@ type Ticker struct { func NewTicker(interval, offset time.Duration) *Ticker { t := &Ticker{} t.baseInterval = interval - t.seed = time.Now().Unix() - t.randGenerator = rand.New(rand.NewSource(t.seed)) // We delay creating the actual time.Ticker in case we need to synchronize // with the next interval boundary. That's done asynchronously below. @@ -72,11 +66,6 @@ func NewTicker(interval, offset time.Duration) *Ticker { return t } -// Seed returns the seed used for the random number generator that controls timing -func (t Ticker) Seed() int64 { - return t.seed -} - // Subscribe returns a channel to which ticks will be delivered. Ticks that // can't be delivered to the channel, because it is not ready to receive, are // discarded. @@ -88,18 +77,6 @@ func (t *Ticker) Subscribe() <-chan time.Time { return c } -// Sample modifies the behavior of the ticker to only tick at a random (and changing) -// point within each specified sampleInterval. All samples still take place at baseInterval -// and offset specified during construction. Turn off sampling by specifying a zero -// duration interval. -func (t *Ticker) Sample(sampleInterval time.Duration) { - t.mux.Lock() - t.sampleFactor = int(sampleInterval / t.baseInterval) - //NOTE: if the sampleInterval is not an integer multiple of baseInterval - //then (via interger division) we round down. - t.mux.Unlock() -} - // Stop stops the ticker. As in time.Ticker, it does not close channels. func (t *Ticker) Stop() { t.tickerMux.Lock() @@ -116,39 +93,17 @@ func (t *Ticker) Stop() { // This could be inlined as an anonymous function, but I think it's easier to // read stacktraces with real function names in them. func (t *Ticker) tick() { - tickCount := -1 - selectedInterval := 0 - samplingOn := false - for { select { case tick := <-t.ticker.C: t.mux.Lock() - sampleFactor := t.sampleFactor - t.mux.Unlock() - - if sampleFactor != 0 { - samplingOn = true - tickCount++ - } else { - samplingOn = false - tickCount = -1 - } - if samplingOn && tickCount%sampleFactor == 0 { - //then we're at the beginning of an interval - selectedInterval = int(t.randGenerator.Int63n(int64(sampleFactor))) - } - if (samplingOn && tickCount%sampleFactor == selectedInterval) || !samplingOn { - //then were at the selected interval OR sampling is off - t.mux.Lock() - for i := range t.chans { - select { - case t.chans[i] <- tick: - default: - } + for i := range t.chans { + select { + case t.chans[i] <- tick: + default: } - t.mux.Unlock() } + t.mux.Unlock() case <-t.stopCh: return } diff --git a/multitick_test.go b/multitick_test.go index b62707e..33eeb1c 100644 --- a/multitick_test.go +++ b/multitick_test.go @@ -4,7 +4,6 @@ package multitick // Please see the LICENSE file for applicable license terms. import ( - "math/rand" "testing" "time" ) @@ -27,59 +26,3 @@ func TestTicker(t *testing.T) { } } } - -func samplingTestor(samplingInterval time.Duration, timesShouldBe []int, t *testing.T) { - // Wait till next second boundary - <-time.After(time.Second - time.Duration(time.Now().Nanosecond())) - - tick := NewTicker(time.Second, time.Millisecond*250) - tick.mux.Lock() - tick.randGenerator = rand.New(rand.NewSource(0)) - tick.mux.Unlock() - c := tick.Subscribe() - tick.Sample(samplingInterval) - i := 0 - - // Wait till first offset in the second - start := <-time.After(time.Duration(250) * time.Millisecond - - time.Duration(time.Now().Nanosecond())) - - for now := range c { - if i > 5 { - tick.Sample(time.Duration(0)) - } - if i > 8 { - tick.Stop() - break - } - tenthsOfSeconds := int(now.Sub(start).Nanoseconds() / 100000000) - t.Log("time (tenths of seconds)", tenthsOfSeconds) - if tenthsOfSeconds != timesShouldBe[i] { - t.Error("Expected", timesShouldBe[i], "but got", tenthsOfSeconds, "for tick.Sample(", samplingInterval, ")") - } - i++ - } -} - -func TestSampling1(t *testing.T) { - samplingTestor(time.Second*2, []int{20, 30, 60, 70, 90, 120, 140, 150, 160, 170}, t) -} - -func TestSampling2(t *testing.T) { - //NOTE: this the the same as the last test b/c of integer rounding. - //This is expected - samplingTestor(time.Second*2+time.Millisecond*999, []int{20, 30, 60, 70, 90, 120, 140, 150, 160, 170}, t) -} - -func TestSampling3(t *testing.T) { - samplingTestor(time.Second*3, []int{30, 40, 80, 120, 130, 160, 190, 200, 210, 220}, t) -} - -func TestSampling4(t *testing.T) { - samplingTestor(time.Second*4, []int{20, 50, 120, 150, 190, 240, 260, 270, 280}, t) -} - -func TestSeed(t *testing.T) { - tick := NewTicker(time.Second, time.Millisecond*250) - tick.Seed() -} From 765dce03b5a651b824b7f8b9cd41c3c0a5de4e7f Mon Sep 17 00:00:00 2001 From: Baron Schwartz Date: Fri, 24 Jan 2014 11:10:00 -0500 Subject: [PATCH 2/2] omit baseInterval --- multitick.go | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/multitick.go b/multitick.go index 61fb9fa..ceb655b 100644 --- a/multitick.go +++ b/multitick.go @@ -12,9 +12,8 @@ import ( // Ticker is a broadcaster for time.Time tick events. type Ticker struct { - mux sync.Mutex // Protects chans slice - chans []chan time.Time - baseInterval time.Duration + mux sync.Mutex // Protects chans slice + chans []chan time.Time tickerMux sync.Mutex // Used to sync start/stop ticker *time.Ticker @@ -29,7 +28,6 @@ type Ticker struct { // is not aligned to an offset, and begins immediately. func NewTicker(interval, offset time.Duration) *Ticker { t := &Ticker{} - t.baseInterval = interval // We delay creating the actual time.Ticker in case we need to synchronize // with the next interval boundary. That's done asynchronously below.