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语言中,值接收者和指针接收者是方法定义中的两种接收者类型,本文主要介绍了go指针接收者和值接收者的区别小结,文中通过示例代码介绍的非常详细,需要的朋友们下... 目录go 指针接收者和值接收者的区别易错点辨析go 指针接收者和值接收者的区别指针接收者和值接收者的

Go 语言中的select语句详解及工作原理

《Go语言中的select语句详解及工作原理》在Go语言中,select语句是用于处理多个通道(channel)操作的一种控制结构,它类似于switch语句,本文给大家介绍Go语言中的select语... 目录Go 语言中的 select 是做什么的基本功能语法工作原理示例示例 1:监听多个通道示例 2:带

Python通过模块化开发优化代码的技巧分享

《Python通过模块化开发优化代码的技巧分享》模块化开发就是把代码拆成一个个“零件”,该封装封装,该拆分拆分,下面小编就来和大家简单聊聊python如何用模块化开发进行代码优化吧... 目录什么是模块化开发如何拆分代码改进版:拆分成模块让模块更强大:使用 __init__.py你一定会遇到的问题模www.

SpringBoot首笔交易慢问题排查与优化方案

《SpringBoot首笔交易慢问题排查与优化方案》在我们的微服务项目中,遇到这样的问题:应用启动后,第一笔交易响应耗时高达4、5秒,而后续请求均能在毫秒级完成,这不仅触发监控告警,也极大影响了用户体... 目录问题背景排查步骤1. 日志分析2. 性能工具定位优化方案:提前预热各种资源1. Flowable

SpringBoot3实现Gzip压缩优化的技术指南

《SpringBoot3实现Gzip压缩优化的技术指南》随着Web应用的用户量和数据量增加,网络带宽和页面加载速度逐渐成为瓶颈,为了减少数据传输量,提高用户体验,我们可以使用Gzip压缩HTTP响应,... 目录1、简述2、配置2.1 添加依赖2.2 配置 Gzip 压缩3、服务端应用4、前端应用4.1 N

Go标准库常见错误分析和解决办法

《Go标准库常见错误分析和解决办法》Go语言的标准库为开发者提供了丰富且高效的工具,涵盖了从网络编程到文件操作等各个方面,然而,标准库虽好,使用不当却可能适得其反,正所谓工欲善其事,必先利其器,本文将... 目录1. 使用了错误的time.Duration2. time.After导致的内存泄漏3. jsO

Spring Boot + MyBatis Plus 高效开发实战从入门到进阶优化(推荐)

《SpringBoot+MyBatisPlus高效开发实战从入门到进阶优化(推荐)》本文将详细介绍SpringBoot+MyBatisPlus的完整开发流程,并深入剖析分页查询、批量操作、动... 目录Spring Boot + MyBATis Plus 高效开发实战:从入门到进阶优化1. MyBatis

MyBatis 动态 SQL 优化之标签的实战与技巧(常见用法)

《MyBatis动态SQL优化之标签的实战与技巧(常见用法)》本文通过详细的示例和实际应用场景,介绍了如何有效利用这些标签来优化MyBatis配置,提升开发效率,确保SQL的高效执行和安全性,感... 目录动态SQL详解一、动态SQL的核心概念1.1 什么是动态SQL?1.2 动态SQL的优点1.3 动态S

go中空接口的具体使用

《go中空接口的具体使用》空接口是一种特殊的接口类型,它不包含任何方法,本文主要介绍了go中空接口的具体使用,具有一定的参考价值,感兴趣的可以了解一下... 目录接口-空接口1. 什么是空接口?2. 如何使用空接口?第一,第二,第三,3. 空接口几个要注意的坑坑1:坑2:坑3:接口-空接口1. 什么是空接

Python如何使用__slots__实现节省内存和性能优化

《Python如何使用__slots__实现节省内存和性能优化》你有想过,一个小小的__slots__能让你的Python类内存消耗直接减半吗,没错,今天咱们要聊的就是这个让人眼前一亮的技巧,感兴趣的... 目录背景:内存吃得满满的类__slots__:你的内存管理小助手举个大概的例子:看看效果如何?1.