Go 1.23 新特性:Timer 和 Ticker 的重要优化

2024-08-22 15:20

本文主要是介绍Go 1.23 新特性:Timer 和 Ticker 的重要优化,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

作者:陈明勇

个人网站:https://chenmingyong.cn

文章持续更新,如果本文能让您有所收获,欢迎点赞收藏加关注本号。 微信阅读可搜《程序员陈明勇》。 这篇文章已被收录于 Github,欢迎大 家Star 催更并持续关注。

前言

Go 1.23 版本在北京时间 2024814 日凌晨 1:03 发布。该版本带来了多项重大更新,具体内容可以参考我之前的文章:Go 1.23 版本发布啦,这些重大更新你一定要知道!。本文将重点介绍其中关于定时器(TimerTicker)的优化。

准备好了吗?准备一杯你最喜欢的咖啡或茶,随着本文一探究竟吧。

程序员陈明勇.jpeg

Timer 和 Ticker 的基本概念

在深入探讨 Go 1.23 版本对 TimerTicker 定时器进行的优化之前,有的读者可能需要了解这两种定时器的基础知识。以下是关于这两种定时器的基本介绍:

  • Timer 是一个一次性的定时器,用于在未来的某一时刻执行一次操作。常用于单次延迟执行任务

  • Tciker 是一个周期性的定时器,用于在固定的时间间隔重复执行任务。它在每个间隔时间到来时,向其通道(Channel)发送当前时间。常用于重复执行任务

垃圾回收的改进

  • Go 1.23 之前的行为: 如果一个 TimerTicker 没有被显式调用 Stop 方法,即使程序不再引用它们,它们也不会立即被垃圾回收。Timer 会在触发后被回收,而 Ticker 则从来不会被自动回收。
  • Go 1.23 新行为: 如果程序不再引用一个 TimerTicker(即没有其他部分的代码持有它们的引用),即使没有调用 Stop 方法,它们也会有资格立即被垃圾回收。这可以减少内存泄漏的风险,因为不再需要显式调用 Stop 也可以保证资源会被回收。

这一更新提高了内存管理效率。以前,如果你创建了一个 TimerTicker,但忘记调用 Stop,这些对象会一直占用内存,直到程序结束。而现在,只要程序不再引用这些对象,它们就会被回收,这样可以避免内存泄漏的问题。

计时器通道行为的变化

  • Go 1.23 之前的行为:TimerTicker 关联的通道带有一个元素缓冲区,这导致 ResetStop 方法在调用后,可能仍会接收到之前准备好的旧值,造成使用上的困难。
  • Go 1.23 新行为: 计时器通道变成了无缓冲的(容量为 0)。这意味着在调用 ResetStop 方法后,Go 可以保证不会再接收到旧的值。这使得 ResetStop 的使用更加可靠。
  • 副作用: 由于通道现在是无缓冲的,lencap 操作返回的值变成了 0,而不是 1。这可能会影响那些依赖轮询通道长度来判断是否能成功接收值的代码。为了适应这种变化,代码应该使用 非阻塞 的接收操作来替代。

这一更新让定时器操作更加可靠和安全。 在 Go 1.23 之前,TimerTicker 的通道是有缓冲的,这意味着即使你调用了 ResetStop,通道中仍可能残留旧的定时信号,这会导致潜在的竞态条件问题。现在改为无缓冲通道后,Go 保证了调用 ResetStop 后,通道不会再收到旧的数据。

我们来看看下面的代码在不同 Go 版本里的运行情况:

package mainimport ("fmt""time"
)func main() {// 程序退出信号quit := make(chan bool)timer := time.NewTimer(2 * time.Second)go func() {// 确保定时器已触发并发送信号time.Sleep(4 * time.Second)// 试图读取通道,看是否有值select {case t := <-timer.C:fmt.Println("接收到定时器信号:", t.Format(time.DateOnly))default:fmt.Println("无信号")}quit <- true}()// 确保定时器已触发并发送信号time.Sleep(3 * time.Second)wasStopped := timer.Stop()if wasStopped {// Go 1.23 或更高版本会走这条分支fmt.Println("定时器未过期,停止成功")} else {// Go 1.23 以前的版本会走这条分支fmt.Println("定时器已经过期并且信号已经发送")}// 等待退出信号<-quit
}

Go 1.22 及之前的版本的运行结果:

定时器已经过期并且信号已经发送
接收到定时器信号: 2024-08-20

由于通道是有缓冲的,在定时器过期时已经发送了信号,因此即使在定时器触发之后调用 Stop() 方法,我们仍然可以从缓冲中接收到信号。

Go 1.23 或更高版本的运行结果:

定时器未过期,停止成功
无信号

由于通道是无缓冲的,信号发送是一个阻塞操作。如果在信号被接收之前调用 Stop() 方法,这将阻止信号的发送。因此,定时器被成功停止,Stop() 返回 true

注意事项

对于 TimerTicker 的这些新行为只有在 Go 模块使用 go.mod 文件并且指定了 Go 1.23.0 或更高版本时才会生效。也就是说如果你的 Go 版本是 Go 1.23,但是你在 go.mod 文件里指定的 Go 版本小于 Go 1.23,那么这些新行为不会生效。

此外,如果你在 go.mod 文件里指定的 Go 版本大于等于 Go 1.23,你可以通过设置环境变量 GODEBUGasynctimerchan=1,从而恢复到之前异步通道的行为。

小结

本文详细介绍了在 Go 1.23 版本中对 TimerTicker 的重要优化,包括两个主要方面:垃圾回收的改进计时器通道行为的变化。改进后的垃圾回收机制有助于防止内存泄漏,而计时器通道的调整则确保在调用 ResetStop 之后,通道不会接收到任何旧数据,提高了定时器操作的可靠性和安全性。

后续将会分主题发布更多关于 Go 1.23 的详细更新内容。关注我,不错过任何精彩内容。

这篇关于Go 1.23 新特性:Timer 和 Ticker 的重要优化的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1096649

相关文章

Go学习记录之runtime包深入解析

《Go学习记录之runtime包深入解析》Go语言runtime包管理运行时环境,涵盖goroutine调度、内存分配、垃圾回收、类型信息等核心功能,:本文主要介绍Go学习记录之runtime包的... 目录前言:一、runtime包内容学习1、作用:① Goroutine和并发控制:② 垃圾回收:③ 栈和

Go语言中泄漏缓冲区的问题解决

《Go语言中泄漏缓冲区的问题解决》缓冲区是一种常见的数据结构,常被用于在不同的并发单元之间传递数据,然而,若缓冲区使用不当,就可能引发泄漏缓冲区问题,本文就来介绍一下问题的解决,感兴趣的可以了解一下... 目录引言泄漏缓冲区的基本概念代码示例:泄漏缓冲区的产生项目场景:Web 服务器中的请求缓冲场景描述代码

Go语言如何判断两张图片的相似度

《Go语言如何判断两张图片的相似度》这篇文章主要为大家详细介绍了Go语言如何中实现判断两张图片的相似度的两种方法,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 在介绍技术细节前,我们先来看看图片对比在哪些场景下可以用得到:图片去重:自动删除重复图片,为存储空间"瘦身"。想象你是一个

Go语言中Recover机制的使用

《Go语言中Recover机制的使用》Go语言的recover机制通过defer函数捕获panic,实现异常恢复与程序稳定性,具有一定的参考价值,感兴趣的可以了解一下... 目录引言Recover 的基本概念基本代码示例简单的 Recover 示例嵌套函数中的 Recover项目场景中的应用Web 服务器中

Go语言中使用JWT进行身份验证的几种方式

《Go语言中使用JWT进行身份验证的几种方式》本文主要介绍了Go语言中使用JWT进行身份验证的几种方式,包括dgrijalva/jwt-go、golang-jwt/jwt、lestrrat-go/jw... 目录简介1. github.com/dgrijalva/jwt-go安装:使用示例:解释:2. gi

go rate 原生标准限速库的使用

《gorate原生标准限速库的使用》本文主要介绍了Go标准库golang.org/x/time/rate实现限流,采用令牌桶算法控制请求速率,提供Allow/Reserve/Wait方法,具有一定... 目录介绍安装API介绍rate.NewLimiter:创建限流器limiter.Allow():请求是否

Go 语言中的 Struct Tag 的用法详解

《Go语言中的StructTag的用法详解》在Go语言中,结构体字段标签(StructTag)是一种用于给字段添加元信息(metadata)的机制,常用于序列化(如JSON、XML)、ORM映... 目录一、结构体标签的基本语法二、json:"token"的具体含义三、常见的标签格式变体四、使用示例五、使用

JDK9到JDK21中值得掌握的29个实用特性分享

《JDK9到JDK21中值得掌握的29个实用特性分享》Java的演进节奏从JDK9开始显著加快,每半年一个新版本的发布节奏为Java带来了大量的新特性,本文整理了29个JDK9到JDK21中值得掌握的... 目录JDK 9 模块化与API增强1. 集合工厂方法:一行代码创建不可变集合2. 私有接口方法:接口

Ubuntu上手动安装Go环境并解决“可执行文件格式错误”问题

《Ubuntu上手动安装Go环境并解决“可执行文件格式错误”问题》:本文主要介绍Ubuntu上手动安装Go环境并解决“可执行文件格式错误”问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未... 目录一、前言二、系统架构检测三、卸载旧版 Go四、下载并安装正确版本五、配置环境变量六、验证安装七、常见

Go语言使用slices包轻松实现排序功能

《Go语言使用slices包轻松实现排序功能》在Go语言开发中,对数据进行排序是常见的需求,Go1.18版本引入的slices包提供了简洁高效的排序解决方案,支持内置类型和用户自定义类型的排序操作,本... 目录一、内置类型排序:字符串与整数的应用1. 字符串切片排序2. 整数切片排序二、检查切片排序状态: