go 的 timer reset

ops/2024/12/22 21:25:10/

在 Go 语言 1.23 版本之前,与Timer(定时器)关联的通道是异步的(有缓冲,容量为 1)。这意味着即使在调用Timer.Stop(停止定时器)或Timer.Reset(重置定时器)并返回后,仍可能接收到过期的时间值。

换句话说,在 Go 1.23 之前,由于定时器的通道特性,可能会出现这样一种情况:即使已经尝试停止或重置定时器,但仍有可能从该定时器的通道中接收到已经过时的时间触发信号,因为这个通道的异步和缓冲特性可能导致一些操作响应不及时或出现意外的信号接收。而在 Go 1.23 版本及之后,可能对定时器的这种行为进行了调整或改进,以避免出现接收过期时间值的情况。

// NewTimer creates a new Timer that will send
// the current time on its channel after at least duration d.
//
// Before Go 1.23, the garbage collector did not recover
// timers that had not yet expired or been stopped, so code often
// immediately deferred t.Stop after calling NewTimer, to make
// the timer recoverable when it was no longer needed.
// As of Go 1.23, the garbage collector can recover unreferenced
// timers, even if they haven't expired or been stopped.
// The Stop method is no longer necessary to help the garbage collector.
// (Code may of course still want to call Stop to stop the timer for other reasons.)
//
// Before Go 1.23, the channel associated with a Timer was
// asynchronous (buffered, capacity 1), which meant that
// stale time values could be received even after [Timer.Stop]
// or [Timer.Reset] returned.
// As of Go 1.23, the channel is synchronous (unbuffered, capacity 0),
// eliminating the possibility of those stale values.
//
// The GODEBUG setting asynctimerchan=1 restores both pre-Go 1.23
// behaviors: when set, unexpired timers won't be garbage collected, and
// channels will have buffered capacity. This setting may be removed
// in Go 1.27 or later.

go 1.23之前 timer.Reset和go 1.23之后 timer.Reset 区别

在 Go 1.23 之前,与计时器相关联的通道是异步的(缓冲,容量为 1),这意味着即使在 Timer.Stop 或 Timer.Reset 返回后,也能接收到过期的时间值。对于使用 NewTimer 创建的计时器,只有在通道(channel)耗尽的定时器停止或过期时才会调用重置。例如,在 Go1.22 及以前的版本上,结合程序来看,计时器 t 的超时时间为 50 毫秒。在 Sleep 方法等待 100 毫秒后,计时器 t 早已经过期,向 t.C 通道发送了一个值。但由于 Reset 方法并不会耗尽通道,因此 <-t.C 不会阻塞,并立即继续程序。
而在 Go 1.23 中,该通道是同步通道(无缓冲,容量为 0),从而消除了出现过期时间值的可能性。Go 1.23 对 time.Timer 和 time.Ticker 的实现进行了重大更改。在 Go 1.23 中,任何调用 Reset 或 Stop 方法的操作,在该调用之前准备的任何过时值都不会在调用后被发送或接收。新的行为仅在主 Go 程序位于使用 Go 1.23.0 或更高版本的 go.mod 文件的模块中时才会启用。当 Go 1.23 构建旧程序时,旧行为仍然有效。新的 GODEBUG 设置 asynctimerchan=1 可以在即使程序在其 go.mod 文件中指定了 Go 1.23.0 或更高版本时,也恢复到异步通道行为。此外,Go 1.23 版本正式发布后,Russ Cox 解决了一直困扰 Go 团队的 Timer/Ticker 的 GC 回收问题,进而解决了 Timer 的 Stop 和 Reset 很难正确使用的问题。

Go1.23 之前 timer.reset 行为

在 Go1.23 之前,对于使用 NewTimer 创建的计时器,只有在通道(channel)耗尽的定时器停止或过期时才会调用重置。例如,在一些特定的场景下,若计时器未处于特定状态就调用 Reset 方法,可能会导致不可预期的结果。这种行为在实际应用中可能会给开发者带来一些困扰,因为开发者需要时刻关注计时器的状态,以确保在正确的时机调用 Reset 方法。这不仅增加了开发的复杂性,还可能导致一些难以排查的错误。比如在一些需要频繁重置计时器的场景中,开发者可能需要额外编写复杂的逻辑来判断计时器的状态,以避免出现错误的重置操作。

Go1.23 之后 timer.reset 行为

在 Go1.23 中,Reset 方法的行为得到了改进。Reset 使计时器重新开始计时,(本方法返回后再)等待时间段 d 过去后到期。如果调用时计时器还在等待中会返回真;如果计时器已经到期或者被停止了会返回假。这一改进使得计时器的使用更加直观和方便。开发者不再需要像在 Go1.23 之前那样时刻关注计时器的状态来判断是否可以进行重置操作。现在,只需要简单地调用 Reset 方法,就可以让计时器重新开始计时。这大大简化了开发过程,减少了出错的可能性。同时,这一改进也提高了代码的可读性和可维护性,使得开发者能够更加专注于业务逻辑的实现,而不是花费大量时间在处理计时器的复杂状态上。
Go1.23 对 timer.reset 的改进使得 Go 语言在计时器的使用上更加便捷和可靠。这一改进体现了 Go 语言不断发展和完善的趋势,为开发者提供了更好的开发体验。

示例

func TestDemo(d *testing.T) {t := time.NewTimer(time.Millisecond * 40)// t已经触发,t.C已经有值time.Sleep(time.Millisecond * 100)start := time.Now()// 对于使用 NewTimer 创建的计时器,只有在 channel 耗尽的定时器停止或过期时才会调用重置// 这里定时器没有被耗尽// Reset 方法并不会耗尽通道,因此 <-t.C 不会阻塞,并立即继续程序ok := t.Reset(time.Millisecond * 40)// 1.23之前是false,false表示已过期/停止// 1.23 中,任何调用 Reset 或 Stop 方法的操作,在该调用之前准备的任何过时值都不会在调用后被发送或接收fmt.Println("ok:", ok)// 等待过期// 1.23之前,立马过期,等待0ms,应为过期的未读取的信号未被清空// 1.23及之后,Reset 会清空过期的未读取的信号,然后等待40ms过期<-t.Cfmt.Printf("wait:%dms\n", time.Since(start).Milliseconds())
}// 在Go1.23中,创建timer之后,Reset会重置timer,可以放心的当成一个新的timer来使用。
// Reset只要没被触发都会返回true,

http://www.ppmy.cn/ops/124061.html

相关文章

基于Arduino的宠物食物分配器

创作本文的初衷是本人的一个养宠物的梦想&#xff08;因为家里人对宠物过敏&#xff0c;因此养宠物的action一直没有落实&#xff09;&#xff0c;但是梦想总是要有的哈哈哈哈哈。上周正好是和一个很好的朋友见面&#xff0c;聊到了养宠物的事情&#xff0c;她大概是讲到了喂宠…

详解RTL design的 CDC和RDC

一、CDC(跨时钟域处理,Clock Domain Crossing) (一)基本原理 时钟域的概念 在芯片设计中,时钟域是由一个时钟信号及其相关逻辑组成的区域。每个时钟域内的电路元件(如寄存器、组合逻辑等)都由同一个时钟信号来同步操作。例如,一个微处理器芯片可能有多个时钟域,如用…

垃圾回收器

一、垃圾回收器的三种类型 1.串行 单线程执行&#xff1a;所有的垃圾回收工作都由单个线程完成&#xff0c;即在进行垃圾回收时&#xff0c;应用程序的其他所有线程都会停止。简单而高效&#xff1a;由于单线程执行&#xff0c;实现上相对简单&#xff0c;适用于小型或中小型…

HTML实现飘动广告效果

上述HTML代码创建了一个简单的网页&#xff0c;其中包含一个可以在页面内自动移动的小方块&#xff08;div元素&#xff09;&#xff0c;并且当鼠标悬停在该方块上时&#xff0c;动画会暂停&#xff1b;当鼠标移开时&#xff0c;动画会继续。以下是代码的详细分析&#xff1a; …

k8s之ingress-nginx-controller安装

作者&#xff1a;程序那点事儿 日期&#xff1a;2024/01/30 01:25 要在master节点上安装 helm repo add ingress-nginx Welcome - Ingress-Nginx Controller helm search repo ingress-nginx helm pull ingress-nginx/ingress-nginx --version 4.4.2 mv ingress-nginx-4.4.…

传智杯 第六届—C

题目描述&#xff1a; 输入两个字符串&#xff0c;从第一字符串中删除第二个字符串中所有的字符。例如&#xff1a;第一个字符串是"They are students."&#xff0c;第二个字符串是”aeiou"。删除之后的第一个字符串变成"Thy r stdnts."。保证两个字符…

诺奖争议升级:Nature杂志揭露提名黑幕,Jürgen公开反对Hinton获诺贝尔奖!

来源 | 机器之心 今年的诺贝尔物理学奖颁给了两位享誉盛名的 AI 研究者 John J. Hopfield 和 Geoffrey E. Hinton&#xff0c;这确实让很多人感到意外。 第一层疑问是&#xff1a;Hinton 和物理学有什么关系吗&#xff1f; 第二层疑问是&#xff1a;AI 科学家是如何提名物理…