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中的时间处理过程

《go中的时间处理过程》:本文主要介绍go中的时间处理过程,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录1 获取当前时间2 获取当前时间戳3 获取当前时间的字符串格式4 相互转化4.1 时间戳转时间字符串 (int64 > string)4.2 时间字符串转时间

Go语言中make和new的区别及说明

《Go语言中make和new的区别及说明》:本文主要介绍Go语言中make和new的区别及说明,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录1 概述2 new 函数2.1 功能2.2 语法2.3 初始化案例3 make 函数3.1 功能3.2 语法3.3 初始化

从入门到精通C++11 <chrono> 库特性

《从入门到精通C++11<chrono>库特性》chrono库是C++11中一个非常强大和实用的库,它为时间处理提供了丰富的功能和类型安全的接口,通过本文的介绍,我们了解了chrono库的基本概念... 目录一、引言1.1 为什么需要<chrono>库1.2<chrono>库的基本概念二、时间段(Durat

Go语言中nil判断的注意事项(最新推荐)

《Go语言中nil判断的注意事项(最新推荐)》本文给大家介绍Go语言中nil判断的注意事项,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧... 目录1.接口变量的特殊行为2.nil的合法类型3.nil值的实用行为4.自定义类型与nil5.反射判断nil6.函数返回的

Go语言数据库编程GORM 的基本使用详解

《Go语言数据库编程GORM的基本使用详解》GORM是Go语言流行的ORM框架,封装database/sql,支持自动迁移、关联、事务等,提供CRUD、条件查询、钩子函数、日志等功能,简化数据库操作... 目录一、安装与初始化1. 安装 GORM 及数据库驱动2. 建立数据库连接二、定义模型结构体三、自动迁

MyBatisPlus如何优化千万级数据的CRUD

《MyBatisPlus如何优化千万级数据的CRUD》最近负责的一个项目,数据库表量级破千万,每次执行CRUD都像走钢丝,稍有不慎就引起数据库报警,本文就结合这个项目的实战经验,聊聊MyBatisPl... 目录背景一、MyBATis Plus 简介二、千万级数据的挑战三、优化 CRUD 的关键策略1. 查

Go语言代码格式化的技巧分享

《Go语言代码格式化的技巧分享》在Go语言的开发过程中,代码格式化是一个看似细微却至关重要的环节,良好的代码格式化不仅能提升代码的可读性,还能促进团队协作,减少因代码风格差异引发的问题,Go在代码格式... 目录一、Go 语言代码格式化的重要性二、Go 语言代码格式化工具:gofmt 与 go fmt(一)

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

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

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

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

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

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