I have a program similar to below program:
package main
import (
"fmt"
"time"
)
func main() {
ch := make(chan string)
go endProgram(ch)
printFunc(ch)
}
func printFunc(ch chan string) {
for {
timeout := time.NewTimer(getTimeoutDuration())
defer timeout.Stop()
select {
case s := <-ch:
fmt.Println(s)
return
case <-timeout.C:
fmt.Println("Current value")
}
}
}
func endProgram(ch chan string) {
time.Sleep(time.Second * 8)
ch <- "Exit function"
}
func getTimeoutDuration() time.Duration {
return time.Second * 3
}
What is the best way to stop the timeout
timer in this case?
I know that above is not the recommended way because it is a bad practice to use defer inside for loop. Alternative is to use time.After
inside the for loop instead of time.NewTimer
as we don't have to stop time.After
. But time.After
causes resource leak if function exits before the timer fires(Source).
if you use context instead of timer, Where cancel only called when exiting function case condition.
package main
import (
"context"
"fmt"
"time"
)
func main() {
ch := make(chan string)
go endProgram(ch)
printFunc(ch)
}
func printFunc(ch chan string) {
for {
ctx, cancel := context.WithTimeout(context.Background(), getTimeoutDuration())
select {
case s := <-ch:
cancel()
fmt.Println(s)
return
case <-ctx.Done():
fmt.Println("Current value")
}
}
}
func endProgram(ch chan string) {
time.Sleep(time.Second * 8)
ch <- "Exit function"
}
func getTimeoutDuration() time.Duration {
return time.Second * 3
}