在for循环内部停止初始化的time.NewTimer。

huangapple go评论88阅读模式
英文:

Stop time.NewTimer initialized inside for loop

问题

我有一个类似下面程序的程序:

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
}

在这种情况下,停止timeout计时器的最佳方法是什么?

我知道上面的方法不是推荐的方式,因为在循环中使用defer是一种不好的做法。替代方法是在循环中使用time.After而不是time.NewTimer,因为我们不需要停止time.After。但是,如果函数在计时器触发之前退出,time.After会导致资源泄漏(来源)。

英文:

I have a program similar to below program:

package main

import (
	&quot;fmt&quot;
	&quot;time&quot;
)

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 := &lt;-ch:
			fmt.Println(s)
			return
		case &lt;-timeout.C:
			fmt.Println(&quot;Current value&quot;)
		}
	}
}

func endProgram(ch chan string) {
	time.Sleep(time.Second * 8)
	ch &lt;- &quot;Exit function&quot;
}

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

答案1

得分: 1

如果您使用上下文而不是计时器,那么只有在退出函数的情况下才会调用取消函数。

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("当前值")
		}
	}
}

func endProgram(ch chan string) {
	time.Sleep(time.Second * 8)
	ch <- "退出函数"
}

func getTimeoutDuration() time.Duration {
	return time.Second * 3
}
英文:

if you use context instead of timer, Where cancel only called when exiting function case condition.

package main

import (
	&quot;context&quot;
	&quot;fmt&quot;
	&quot;time&quot;
)

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 := &lt;-ch:
			cancel()
			fmt.Println(s)
			return
		case &lt;-ctx.Done():
			fmt.Println(&quot;Current value&quot;)
		}
	}
}

func endProgram(ch chan string) {
	time.Sleep(time.Second * 8)
	ch &lt;- &quot;Exit function&quot;
}

func getTimeoutDuration() time.Duration {
	return time.Second * 3
}

huangapple
  • 本文由 发表于 2021年8月19日 19:44:14
  • 转载请务必保留本文链接:https://go.coder-hub.com/68847230.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定