-1

at the moment I am using a for loop like this

for ; true; <-time.After(duration)

the first time it is executed instantly, then by <-time.After(duration)

Now I need to rewrite this function so that I can stop it with a channel. By default, this is done using select, but it waits for the <-time.After(duration) already at the first iteration

for {
    select {
    case <-done:
        return
    case t := <-time.After(duration):
        fmt.Println("Tick at", t)
    }
}

how i can solve it?

9
  • 2
    Something like this go.dev/play/p/6ruCT0q1ssF? Btw. what is "unsanate"?
    – mkopriva
    Commented Nov 17, 2022 at 9:30
  • @mkopriva just stop, T9
    – ERVIN228
    Commented Nov 17, 2022 at 9:36
  • 1
    You could also just keep the original for loop and at the top of its body have a select on the done channel with a default case that is empty, e.g. go.dev/play/p/3QuY40ikkKn
    – mkopriva
    Commented Nov 17, 2022 at 9:42
  • Would you be able to add the full sample adding how you are triggering the mentioned selection block and how you are sending messages over the done channel?
    – tmarwen
    Commented Nov 17, 2022 at 9:47
  • 3
    @ERVIN228 I did not say nor imply that done is a context, it clearly isn't since you're doing the receive operation on it and you cannot receive from a context instance. Furthermore I'm not sure what exactly you're trying to explain, it would be much easier if you provide a minimal reproducible example. Show the code, show the problem. Not in the comments, but in the question, this one or a new one.
    – mkopriva
    Commented Nov 17, 2022 at 10:42

2 Answers 2

0

The select statement will cycle through the different channels checking one by one if the channel is ready for read or write.

In case no channel is ready for read or write, the select statement will block waiting for one of the channels readiness unless there is a default statement which in your case should be a no-op:

for {
    select {
    case <-done:
        return
    case t := <-time.After(duration):
        fmt.Println("Tick at", t)
    default: // cycle back
    }
}
2
  • You never want a default in an empty for+select like that, because you have turned it into a busy loop, are defeating the purpose of the time.After, and will quickly overwhelm the scheduler and gc.
    – JimB
    Commented Nov 17, 2022 at 14:15
  • I totally agree and I would not implement such a logic myself as it totally collapses the purpose of time.After. My point was to adapt the main author snippet with proper explanation.
    – tmarwen
    Commented Nov 17, 2022 at 15:24
0

Initially set zero delay and then change it on first execution

duration := DESIRED_DURATION * 0
for {
    select {
    case <-done:
        return
    case t := <-time.After(duration):
        duration = DESIRED_DURATION 
        fmt.Println("Tick at", t)
    }
}

Not the answer you're looking for? Browse other questions tagged or ask your own question.