Home > front end >  Mixing timer.Ticker with timer.Tick / timer.After; ignores timer from Tick/After
Mixing timer.Ticker with timer.Tick / timer.After; ignores timer from Tick/After

Time:09-05

I'm playing around with channels and I'm running into something here. I have a loop, I want to stop after a set period of time, say 5 seconds, I also want to debounce iterations by say 300 milliseconds.

func pump() <-chan interface{} {
    c := make(chan interface{})

    // use for loop
    // stop after 5 seconds

    d := time.NewTicker(time.Millisecond * 2000)

    go func() {

    myLoop:
        for {
            select {
            case <-time.After(time.Second * 5):
                fmt.Println("Its five seconds")
                close(c)
                d.Stop()
                break myLoop
            default:
                c <- rand.Int()
                <-d.C
                fmt.Println("After wait / debounce")
            }
        }
    }()

    return c
}

While the above seems to debounce, it never triggers the case for hitting 5 seconds. I have similar results for time.Tick(time.Second * 5)

func pump() <-chan interface{} {
    c := make(chan interface{})

    // use for loop
    // stop after 5 seconds

    d := time.NewTicker(time.Millisecond * 2000)
    t := time.NewTicker(time.Second * 5)

    go func() {

    myLoop:
        for {
            select {
            case <-t.C:
                fmt.Println("Its five seconds")
                close(c)
                t.Stop()
                d.Stop()
                break myLoop
                // case <-d.C:
                //  fmt.Println("its a sleep")
            default:
                c <- rand.Int()
                //  // slow down
                <-d.C
                //  fmt.Println("After 3000 milliseconds")
            }
        }
    }()

    return c
}
func pump() <-chan interface{} {
    c := make(chan interface{})

    // use for loop
    // stop after 5 seconds

    d := time.NewTicker(time.Millisecond * 2000)
    t := time.NewTicker(time.Second * 5)

    go func() {

    myLoop:
        for {
            select {
            case <-t.C:
                // case <-time.After(time.Second * 5):
                fmt.Println("Its five seconds")
                close(c)
                t.Stop()
                d.Stop()
                break myLoop
            case <-d.C:
                c <- rand.Int()
            }
        }
    }()

    return c
}

The above works for me; using another ticker. I dont udnerstand why this works where the former fails, especially as a time.Tick() is described in the documentation as being equivalent to a time.NewTicker() with only the channel C exposed.

What am I missing here? are the code snippets significantly different?

CodePudding user response:

As per my comment:

for {
   select {
      case <-time.After(time.Second * 5):
         ...
      default:
         ...
   }
}

Will create a new timer (time.After) each iteration. This means that the timer will never fire (because the default) case will always be selected. You can prevent this by creating the timer outside of the loop (playground):

timer := time.After(time.Second * 5)

myLoop:
for {
   select {
      case <-timer:
         break myLoop
      default:
         ...
   }
}

Your second example worked OK for me (see the previously referenced playground). Note that I'm unsure if any of these will accomplish the result you are looking for because that was not really defined.

  • Related