0

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).

Jonathan Hall
  • 75,165
  • 16
  • 143
  • 189
Abhay Gupta
  • 786
  • 12
  • 30
  • 4
    in this case, you better use context with timeout... because 1) your for is irrelevant, to a new ticker (which starts every single iteration). defer will work on **function exits** , not **scope exits**. – Oleg Butuzov Aug 19 '21 at 11:46

1 Answers1

1

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
}
Oleg Butuzov
  • 4,795
  • 2
  • 24
  • 33