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项目中的GOPROXY设置

    Go项目中的GOPROXY设置

    GOPROXY是Go语言中用于指定模块代理服务器的环境变量,设置GOPROXY可以通过操作系统环境变量、Go命令行参数或Go环境配置文件进行,感兴趣的可以了解一下
    2024-09-09
  • Golang Map实现赋值和扩容的示例代码

    Golang Map实现赋值和扩容的示例代码

    这篇文章主要介绍了Golang Map实现赋值和扩容的示例代码,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-04-04
  • Golang中实现简单的Http Middleware

    Golang中实现简单的Http Middleware

    本文主要针对Golang的内置库 net/http 做了简单的扩展,实现简单的Http Middleware,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-07-07
  • GoLang 中的随机数的示例代码

    GoLang 中的随机数的示例代码

    本篇文章主要介绍了GoLang 中的随机数的示例代码,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-03-03
  • go语言vscode集成开发环境搭建

    go语言vscode集成开发环境搭建

    本文将介绍如何使用VSCode搭建Go语言开发环境,Go语言是一种简洁高效的编程语言,而VSCode是一款轻量级的集成开发环境,二者的结合可以提供良好的开发体验,
    2023-08-08
  • golang中数组与切片的区别详析

    golang中数组与切片的区别详析

    数组是固定长度,常量,切片长度是可以改变,所以是一个可变的数组,下面这篇文章主要给大家介绍了关于golang中数组与切片区别的相关资料,文中通过实例代码介绍的非常详细,需要的朋友可以参考下
    2022-11-11
  • 解决golang post文件时Content-Type出现的问题

    解决golang post文件时Content-Type出现的问题

    这篇文章主要介绍了解决golang post文件时Content-Type出现的问题,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2021-05-05
  • GoFrame ORM原生方法操作示例

    GoFrame ORM原生方法操作示例

    这篇文章主要为大家介绍了GoFrame ORM原生方法操作示例,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-06-06
  • Go语言循环遍历含有中文的字符串的方法小结

    Go语言循环遍历含有中文的字符串的方法小结

    这篇文章主要介绍了Go语言循环遍历含有中文的字符串的几种方法,文章通过代码示例讲解的非常详细,具有一定的参考价值,感兴趣的小伙伴跟着小编一起来看看吧
    2023-07-07
  • Go语言的数据结构转JSON

    Go语言的数据结构转JSON

    本文主要介绍了Go语言的数据结构转JSON,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-01-01

最新评论