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. 洛谷 NOIP 2023 模拟赛 T2 汪了个汪

    洛谷 NOIP 2023 模拟赛 T2 汪了个汪 考试建出正解图不知道怎么处理,题解区樱雪喵博客薄纱. 樱雪喵题解链接 Ps:笔者语文爆炸,不建议阅读本文 思路 首先你会发现,一共有 \(\frac{ ...

  2. php open_basedir的使用

    今天跨省问为什么file_exists检测一个相对路径的文件无法获取到true,文件明明有,但是获取不到,我看了一下,感觉可能是因为这个文件是软链接过来的有关系. 然后他找了找发现是和这么一个文件.u ...

  3. 打包jar 程序,同时将依赖报一起打包

    1.概述 有些时候,我们打包一个java 程序,我需要将所有的依赖也一起打包,这样执行起来方便. 2.我们可以使用maven 插件实现 <build> <plugins> &l ...

  4. 【前端】‘opencollective-postinstall‘ 不是内部或外部命令,也不是可运行的程序

    问题 'opencollective-postinstall' 不是内部或外部命令,也不是可运行的程序 解决办法 npm install --save opencollective-postinsta ...

  5. 前端每日一知之css常用布局单位

    脑图在线链接 本文内容依据[js每日一题]公众号精彩文章总结而来

  6. 授权|取消授权MYSQL数据库用户权限

    授权 queryusr用户查询test数据库 grant select on test.* to queryusr@'%'; flush PRIVILEGES 收回queryusr用户查询test数据 ...

  7. AT_kupc2019_g ABCのG問題题解

    这题的难度不怎么好说,不过我认为还是挺简单的. 我们可以把答案看成由多个子图构成的图,这样我们只需要手打一个小子图,从中推出完整的答案. - 把小于子图范围的地方填上子图的字母 - 如果这个点的横坐标 ...

  8. PDF 的一些资料

    PDF Succinctly https://www.syncfusion.com/ebooks/pdf Create PDFs in ASP.NET - getting started with i ...

  9. 在 .net core 与 .net framework 应用之间共享库

    如果你对 .net core 做了任何重要的提交,你就需要为 .net framework 共享同样的库,因为,.net core 是一个新兴的系统生态系统,仍然缺失很多部分. 在混合系统中,你有两个 ...

  10. 为什么C#越来越恶心

    看看这个 再看这些 more 老子声明个空函数,没有访问数据请改为 static,真是越来越智障 为什么一个活泼的语言越搞越像 C++? C# 发明了各种可爱的小玩意儿,尤其是 async/await ...