golang1.23版本之前 Timer Reset方法无法正确使用

golang1.23 之前 Reset ​到底有什么问题

golang 的 time.Reset 文档中有这么一句话,为了防止文档更新而导致内容变动,这里粘贴出来:

Before Go 1.23, the only safe way to use Reset was to [Stop] and explicitly drain the timer first. See the NewTimer documentation for more details.
在Go 1.23 之前,唯一安全使用Reset函数的方式是:在使用之前调用Stop函数并且明确的从timer的channel中抽取出东西。

虽然文档中已经告诉了正确使用的方式,但是实际上在真正的代码中无法达到这个要求,参考下方代码(来源代码来源):

//consumer
go func() {
// try to read from channel, block at most 5s.
// if timeout, print time event and go on loop.
// if read a message which is not the type we want(we want true, not false),
// retry to read.
timer := time.NewTimer(time.Second * 5)
for {
// timer may be not active, and fired
if !timer.Stop() {
select {
case <-timer.C: //try to drain from the channel,尝试抽取,由于使用select,因此这里可以保证:不阻塞 + 一定抽取成功
default:
}
}
timer.Reset(time.Second * 5) //重置定时器
select {
case b := <-c:
if b == false {
fmt.Println(time.Now(), ":recv false. continue")
continue
}
//we want true, not false
fmt.Println(time.Now(), ":recv true. return")
return
case <-timer.C:
fmt.Println(time.Now(), ":timer expired")
continue
}
}
}()

在上面的代码中,我们按照文档的要求,在 timer.Reset ​之前已经调用了 Stop ​函数,且如果 Stop 成功(返回 true),还尝试抽取 timer,看起来似乎没问题的代码中仍然存在问题。

问题的关键在于:当 Ticket 触发的时候,设置定时器状态的操作和发送 channel 的操作并不是原子的,见 runOneTimer 函数

异常情况:尝试抽取 channel 在 发送 channel 之前,这样会导致 Reset 之前并没有真正的清空 timer,后一次的 timer.C 还没到触发时间就异常的触发了!

golang1.23 之前到底应该如何正确的使用 Reset

实际上简洁点就这么写,每次一个新的局部变量 Timer​ 结构体没压力,非要复用使用 Reset 的可读性太差了,对维护者不友好,而且习惯了不好的写法,哪天一不小心就写出问题了~

go func() {
for {
func() {
timer := time.NewTimer(time.Second * 2)
defer timer.Stop() select {
case b := <-c:
if !b {
fmt.Println(time.Now(), "work...")
}
case <-timer.C: // BBB: normal receive from channel timeout event
fmt.Println(time.Now(), "timeout")
}
}()
}
}()

参考:

https://tonybai.com/2016/12/21/how-to-use-timer-reset-in-golang-correctly/

https://www.v2ex.com/t/794283

golang1.23版本之前 Timer Reset方法无法正确使用的更多相关文章

  1. Git恢复之前版本的两种方法reset、revert

    实战 回退 1.删除之前的提交 git reset --hard id 推送到远程 git push -f [git log中确实删除了,但是拿到可以恢复] 2.不删除之前的提交 git revert ...

  2. ubuntu查看mysql版本的几种方法

    ubuntu查看mysql版本的几种方法 mysql 1:在终端下:mysql -V(大写) //代码 $ mysql -V mysql Ver 14.14 Distrib 5.5.46, for d ...

  3. 【转】ubuntu 配置 java jdk1.8 环境,增加多版本 jdk 和切换方法

    一.安装java jdk1.8 1.添加软件源 sudo add-apt-repository ppa:webupd8team/java 2.更新软件源 sudo apt-get update 3.安 ...

  4. git 本地库推送远程库 版本冲突的解决方法

    参考: http://blog.csdn.net/shiren1118/article/details/7761203 github上的版本和本地版本冲突的解决方法 $ git push XXX ma ...

  5. 更新xcode后插件失效问题——不针对特定版本的通用解决方法

    一.Xcode更新后插件失效的原理 1.每次更新Xcode后插件都会失效,其实插件都还在这个目录好好的躺着呢: ~/Library/Application Support/Developer/Shar ...

  6. CSS Reset方法

    CSS Reset 即重设浏览器的样式.在各种浏览器中,都会对CSS的选择器默认一些数值,譬如当h1没有被设置数值时,显示一定大小. 但并不是所有的浏览器都使用一样的数值,所以,有了CSS Reset ...

  7. Linux下查看内核、CPU、内存及各组件版本的命令和方法

    Linux下查看内核.CPU.内存及各组件版本的命令和方法 Linux查看内核版本: uname -a                        more /etc/*release       ...

  8. InputStream中通过mark和reset方法重复利用缓存

    通过缓存InputStream可重复利用一个InputStream,但是要缓存一整个InputStream内存压力可能是比较大的.如果第一次读取InputStream是用来判断文件流类型,文件编码等用 ...

  9. reset()方法的使用、jq下面reset()的正确使用方法

    reset()是 原生js的的方法,所有浏览器都支持,而且必须是form元素包括下的表单元素,但是JQuery中没有reset方法, 效果图:  错误用法: 正确用法: js用法: document. ...

  10. 2个版本并存的python使用新的版本安装django的方法

    2个版本并存的python使用新的版本安装django的方法 默认是使用 pip install django 最新版的django会提示  要求python版本3.4以上,系统默认的版本是2.7.5 ...

随机推荐

  1. 鸿蒙Navigation拦截器实现页面跳转登录鉴权方案

    我们在进行页面跳转时,很多情况下都得考虑登录状态问题,比如进入个人信息页面,下单交易页面等等.在这些场景下,通常在页面跳转前,会先判断下用户是否已经登录,若已登录,则跳转到相应的目标页面,若没有登录, ...

  2. C#/.NET/.NET Core技术前沿周刊 | 第 13 期(2024年11.11-11.17)

    前言 C#/.NET/.NET Core技术前沿周刊,你的每周技术指南针!记录.追踪C#/.NET/.NET Core领域.生态的每周最新.最实用.最有价值的技术文章.社区动态.优质项目和学习资源等. ...

  3. AT cf17 final J Tree MST

    AT cf17 final J Tree MST 考场上想出的黑题,然而写挂了-- 思路 考场推出 boruvka 算法,会的直接跳过就好. 结论:一个点向另外一个点连出的最小边,一定在最小生成树上. ...

  4. .NET9 - 新功能体验(一)

    被微软形容为"迄今为止最高效.最现代.最安全.最智能.性能最高的.NET版本"--.NET 9已经发布有一周了,今天想和大家一起体验一下新功能. 此次.NET 9在性能.安全性和功 ...

  5. An expression evaluator

    An expression evaluator  Download source code (17 kb) Two weeks ago, I saw an article on codeproject ...

  6. 简述GoLang优势与生态

    开门见山,一睹golang的风采 性能优势 部署运维成本低 编码格式统一:测试简单 1. 性能优势 Go 语言被称为是:"21世纪的C语言",虽然这个帽子戴的有点高,不妨这里给大家 ...

  7. 解析JDBC使用查询MySQL【非流式、流式、游标】

    解析JDBC使用游标查询MySQL 使用jdbc查询MySQL数据库,如果使用游标或者流式查询的话,则可以有效解决OOM的问题,否则MySQL驱动就会把数据集全部查询出来加载到内存里面,这样在大数据的 ...

  8. 关于Popup的小坑坑

    在做一个自定义的输入搜索框,用textbox+popup来实现.其中有一个小需求,当textbox激活并且没有文本输入的时候,也要显示popup.很自然的想到了使用IsKeyboardFocusedC ...

  9. Element Plus组件el-select回显异常

    前情 公司有经常需要做一些后台管理页面,我们选择了Element Plus,它是基于 Vue 3,面向设计师和开发者的组件库,是Vue框架生态中比较火的UI组件库,组件库丰富易用,组件链接:一个 Vu ...

  10. 修改QScrollArea背景色透明,且不影响子控件,在Edit Style Sheet中修改

    在QScrollArea或者父控件中设置: QScrollArea{ background-color:transparent; } 在scrollAreaWidgetContents控件或者父控件中 ...