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 催更。

推荐阅读

相关推荐
王中阳Go11 小时前
Golang框架封神榜!GitHub星标TOP8大比拼,选对框架少走3年弯路
后端·面试·go
王中阳Go12 小时前
05 Go Eino AI应用开发实战 | Docker 部署指南
人工智能·后端·go
Way2top13 小时前
Go语言动手写Web框架 - Gee第三天 前缀树路由Router
go
王中阳Go13 小时前
06 Go Eino AI应用开发实战 | Eino 框架核心架构
人工智能·后端·go
王中阳Go2 天前
告别调包侠!2026年Go/Java程序员的AI架构师实战转型指南
后端·go
王中阳Go2 天前
攻克制造业知识检索难题:我们如何用Go+AI打造高可用RAG系统,将查询效率提升600%
人工智能·后端·go
喵个咪2 天前
开箱即用的 GoWind Admin|风行,企业级前后端一体中后台框架:用 JavaScript/Lua 解锁动态业务扩展能力
javascript·go·lua
喵个咪2 天前
开箱即用的 GoWind Admin|风行,企业级前后端一体中后台框架:kratos-bootstrap 入门教程(类比 Spring Boot)
后端·微服务·go
王中阳Go2 天前
12 Go Eino AI应用开发实战 | 消息队列架构
人工智能·后端·go
香吧香2 天前
go项目使用go build 与 MakeFile 构建项目
go