golang1.23版本之前 Timer Reset方法无法正确使用
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/
golang1.23版本之前 Timer Reset方法无法正确使用的更多相关文章
- Git恢复之前版本的两种方法reset、revert
实战 回退 1.删除之前的提交 git reset --hard id 推送到远程 git push -f [git log中确实删除了,但是拿到可以恢复] 2.不删除之前的提交 git revert ...
- ubuntu查看mysql版本的几种方法
ubuntu查看mysql版本的几种方法 mysql 1:在终端下:mysql -V(大写) //代码 $ mysql -V mysql Ver 14.14 Distrib 5.5.46, for d ...
- 【转】ubuntu 配置 java jdk1.8 环境,增加多版本 jdk 和切换方法
一.安装java jdk1.8 1.添加软件源 sudo add-apt-repository ppa:webupd8team/java 2.更新软件源 sudo apt-get update 3.安 ...
- git 本地库推送远程库 版本冲突的解决方法
参考: http://blog.csdn.net/shiren1118/article/details/7761203 github上的版本和本地版本冲突的解决方法 $ git push XXX ma ...
- 更新xcode后插件失效问题——不针对特定版本的通用解决方法
一.Xcode更新后插件失效的原理 1.每次更新Xcode后插件都会失效,其实插件都还在这个目录好好的躺着呢: ~/Library/Application Support/Developer/Shar ...
- CSS Reset方法
CSS Reset 即重设浏览器的样式.在各种浏览器中,都会对CSS的选择器默认一些数值,譬如当h1没有被设置数值时,显示一定大小. 但并不是所有的浏览器都使用一样的数值,所以,有了CSS Reset ...
- Linux下查看内核、CPU、内存及各组件版本的命令和方法
Linux下查看内核.CPU.内存及各组件版本的命令和方法 Linux查看内核版本: uname -a more /etc/*release ...
- InputStream中通过mark和reset方法重复利用缓存
通过缓存InputStream可重复利用一个InputStream,但是要缓存一整个InputStream内存压力可能是比较大的.如果第一次读取InputStream是用来判断文件流类型,文件编码等用 ...
- reset()方法的使用、jq下面reset()的正确使用方法
reset()是 原生js的的方法,所有浏览器都支持,而且必须是form元素包括下的表单元素,但是JQuery中没有reset方法, 效果图: 错误用法: 正确用法: js用法: document. ...
- 2个版本并存的python使用新的版本安装django的方法
2个版本并存的python使用新的版本安装django的方法 默认是使用 pip install django 最新版的django会提示 要求python版本3.4以上,系统默认的版本是2.7.5 ...
随机推荐
- 4G模组AT指令 | MQTT应用指南!
今天,老师傅讲的是关于4G模组AT指令之MQTT应用,以4G模组Air780E为例: 一.MQTT 协议简介 1.1 MQTT 概述 MQTT 是一种轻量级的消息传输协议,旨在在物联网(IoT)应用中 ...
- Python新手教学
## 简介Python是一种简单易学的编程语言,广泛应用于各个领域,包括Web开发.数据科学.人工智能等.本文将为新手程序员提供Python基础知识的教学,包括变量.数据类型.条件语句.循环.函数等内 ...
- vagrant 环境安装(前置篇)
ubuntu可以直接 apt 源查找 sudo apt search vagrant 直接就 sudo apt-get install vagrant 如果版本不是 2.2.6 可以去 https:/ ...
- 秒懂Redis
一.redis简介 Redis 是C语言开发的一个开源高性能键值对的内存数据库,可以用来做数据库.缓存.消息中间件等场景,是一种NoSQL(not-only sql,非关系型数据库)的数据库 二.Re ...
- Blazor 组件库 BootstrapBlazor 中AutoFill组件介绍
组件介绍 AutoFill 自动填充组件 通过智能感应提示选项,选中后自动填充表单. 他的代码如下: <AutoFill TValue="Foo" Value="M ...
- 鸿蒙ArkUI-X已更新适配API13啦
ArkUI-X 5.0.1 Release版配套OpenHarmony 5.0.1 Rlease,API 13,新增适配部分API 13接口支持跨平台:框架能力进一步完善,支持Android应用非压缩 ...
- Android开发重要知识点
一.网络 1.https原理 2.tcp/ip协议 三次握手:https://www.cnblogs.com/cenglinjinran/p/8482412.html 四次挥手:https://www ...
- asp.net 简单日志收集
做开发的都知道,完整的日志记录对问题的解决,回溯是多么的重要,多么的不可缺少. 那么我们怎么记录完整的日志? 今天,我们来说一说问题:从哪里开始记录呢?在哪里保存呢? IHttpModule,这个大家 ...
- OSG开发笔记(三十七):OSG基于windows平台msvc2017x64编译器官方稳定版本OSG3.4.1搭建环境并移植Demo
前言 自行编译的osg版本插件比较多,如果对版本没有特定要求,但是对环境编译器有特定要求,可以反向融合编译器符合要求的osg版本. OSG下载过程 osg官网:http://www.osg ...
- Nuxt.js 应用中的 beforeResponse 事件钩子
title: Nuxt.js 应用中的 beforeResponse 事件钩子 date: 2024/12/5 updated: 2024/12/5 author: cmdragon excerpt: ...