Go1.23 新特性:time.Reset 解决了过期时间值的天坑!

大家好,我是煎鱼

在 Go1.23 以前,标准库 time 除了 After 方法外。还有另外一个问题,那就是 StopReset 方法不太靠谱。

以至于大家在一些特殊场景下总是这踩点坑,那踩点坑。无论如何,解决了就值得我们给 rsc 鼓掌!

问题背景

最早的反馈来自 2016 年的 time: document proper usage of Timer.Stop,随后在 2020 年终于有人正式提出且下面这个问题

问题的代码示例:

go 复制代码
func main() {
	timeout := 50 * time.Millisecond
	t := time.NewTimer(timeout)

	time.Sleep(100 * time.Millisecond)

	start := time.Now()
	t.Reset(timeout)
	<-t.C

	fmt.Printf("煎鱼已经消失:%dms\n", time.Since(start).Milliseconds())
}

先暂停,思考一下。

这段程序输出的结果是什么?是 "煎鱼已经消失:100ms" 吗,还是 50ms?

Go1.22 及以前的版本下,输出结果如下:

shell 复制代码
煎鱼已经消失:0ms

结果是:"煎鱼已经消失:0ms"。是不是有些与想象中不一样。

原因分析

程序走读

在 Go1.22 及以前的版本上,Go 官方文档在 Reset 方法说明上,明确要求:对于使用 NewTimer 创建的计时器,只有在通道(channel)耗尽的定时器停止或过期时才会调用重置。

结合程序来看,计时器 t 的超时时间为 50 毫秒。在 Sleep 方法等待 100 毫秒后,计时器 t 早已经过期,向 t.C 通道发送了一个值。

但由于 Reset 方法并不会耗尽通道,因此 <-t.C 不会阻塞并立即继续程序。人家压根没阻塞,程序想必就直接输出了 "煎鱼已经消失:0ms"。

官方根因

在 Go1.23 之前,与计时器相关联的通道是异步的(缓冲,容量为 1),这意味着即使在 Timer.StopTimer.Reset 返回后,也能接收到过期的时间值。(导致程序与预期不符的根本原因)

从 Go1.23 开始,该通道是同步通道(无缓冲,容量为 0),从而消除了出现过期时间值的可能性。

Go1.23 终于正常了!

我们回到新发布的 Go1.23 RC 版本,该问题终于被修复,皆大欢喜!

当我们再次运行上述程序后,输出结果:

复制代码
煎鱼已经消失:50ms

程序运行结果符合预期。

总结

历经了 8 年左右,从在 Go1.7 左右发现到愿意承认这个问题,再到再 Go1.23 真正去修复 Timer,感觉也是非常不容易的。

本次在 Go1.23 起,Time 的两个坑 After 和 Reset 都得到了解决,后面大家也可以省心不少了。唯一遗憾的就是明知有问题,解决的还是比较久了(可能优先级比较低?)。

  • 本文作者:煎鱼
  • 公众号:脑子进煎鱼了
  • 联系方式(微信号):cJY0728(加我拉你进技术交流群)

文章持续更新,可以微信搜【脑子进煎鱼了】阅读,本文 GitHub github.com/eddycjy/blo... 已收录,学习 Go 语言可以看 Go 学习地图和路线,欢迎 Star 催更。

推荐阅读

相关推荐
研究司马懿15 小时前
【云原生】Gateway API高级功能
云原生·go·gateway·k8s·gateway api
梦想很大很大1 天前
使用 Go + Gin + Fx 构建工程化后端服务模板(gin-app 实践)
前端·后端·go
lekami_兰1 天前
MySQL 长事务:藏在业务里的性能 “隐形杀手”
数据库·mysql·go·长事务
却尘2 天前
一篇小白也能看懂的 Go 字符串拼接 & Builder & cap 全家桶
后端·go
ん贤2 天前
一次批量删除引发的死锁,最终我选择不加锁
数据库·安全·go·死锁
mtngt112 天前
AI DDD重构实践
go
Grassto4 天前
12 go.sum 是如何保证依赖安全的?校验机制源码解析
安全·golang·go·哈希算法·go module
Grassto5 天前
11 Go Module 缓存机制详解
开发语言·缓存·golang·go·go module
程序设计实验室6 天前
2025年的最后一天,分享我使用go语言开发的电子书转换工具网站
go
我的golang之路果然有问题6 天前
使用 Hugo + GitHub Pages + PaperMod 主题 + Obsidian 搭建开发博客
golang·go·github·博客·个人开发·个人博客·hugo