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

 更新时间:2025年01月27日 09:53:29   作者:思wu邪  
在Go 1.23之前,使用`time.Reset`函数时需要先调用`Stop`并明确从timer的channel中抽取出东西,以避免潜在的问题,然而,这在实际代码中难以实现,因为设置定时器状态和发送channel的操作并不是原子的,在某些情况下,这会导致timer在不应该触发时提前触发

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方法无法正确使用的文章就介绍到这了,更多相关golang Timer Reset方法无法正确使用内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Go语言二进制文件的读写操作

    Go语言二进制文件的读写操作

    本文主要介绍了Go语言二进制文件的读写操作,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-04-04
  • go语言数据类型之字符串string

    go语言数据类型之字符串string

    这篇文章介绍了go语言数据类型之字符串string,文中通过示例代码介绍的非常详细。对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2022-07-07
  • golang反向代理设置host不生效的问题解决

    golang反向代理设置host不生效的问题解决

    在使用golang的httputil做反向代理的时候,发现一个奇怪的现象,上游网关必须要设置host才行,不设置host的话,golang服务反向代理请求下游会出现http 503错误,接下来通过本文给大家介绍golang反向代理设置host不生效问题,感兴趣的朋友一起看看吧
    2023-05-05
  • Go中regexp包常见的正则表达式操作

    Go中regexp包常见的正则表达式操作

    本文主要介绍了Go中regexp包常见的正则表达式操作,包括匹配、查找、替换和分割字符串等,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2025-02-02
  • Golang中json和jsoniter的区别使用示例

    Golang中json和jsoniter的区别使用示例

    这篇文章主要介绍了Golang中json和jsoniter的区别使用示例,本文给大家分享两种区别,结合示例代码给大家介绍的非常详细,感兴趣的朋友跟随小编一起看看吧
    2023-12-12
  • GO语言实现简单TCP服务的方法

    GO语言实现简单TCP服务的方法

    这篇文章主要介绍了GO语言实现简单TCP服务的方法,实例分析了Go语言实现TCP服务的技巧,需要的朋友可以参考下
    2015-03-03
  • golang实现简易的分布式系统方法

    golang实现简易的分布式系统方法

    这篇文章主要介绍了golang实现简易的分布式系统方法,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-10-10
  • Golang WebView跨平台的桌面应用库的使用

    Golang WebView跨平台的桌面应用库的使用

    Golang WebView是一个强大的桌面应用库,本文介绍了Golang WebView的特点和使用方法,并列举示例详细的介绍了其在实际项目中的应用,具有一定的参考价值,感兴趣的可以了解一下
    2024-03-03
  • 浅析Golang切片截取功能与C++的vector区别

    浅析Golang切片截取功能与C++的vector区别

    这篇文章主要介绍了Golang中切片的截取功能与C++中的vector有什么区别,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习吧
    2022-10-10
  • go实现图片拼接与文字书写的方法实例

    go实现图片拼接与文字书写的方法实例

    这篇文章主要给大家介绍了关于go实现图片拼接与文字书写的相关资料,文中通过实例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2022-01-01

最新评论