支持首次触发的 Go Ticker

促使我写这篇文章主要是在写一个关于虚拟货币账户监控的项目时使用 Ticker 的问题。

Ticker 的问题

如果用过 Ticker 的朋友会知道,创建 Ticker 后并不会马上执行,而是会等待一个时间 d,这就是创建时的间隔时间。如果间隔时间很短这基本上不会有太大问题,但是如果对首次执行时间有要求,就会很麻烦。例如以下这个案例:


package main

import (
    "fmt"
    "sync"
    "time"
)

func main() {
    ts := time.NewTicker(5 * time.Second)
    fmt.Println("start_time#", time.Now().Unix())
    chanClose := make(chan struct{})
    var wg sync.WaitGroup
    wg.Add(1)
    go func() {
        defer wg.Done()
        for {
            select {
            case

它将返回以下内容:

start_time# 1656860176
run_time# 1656860181
run_time# 1656860186

为了方便演示我们在事例中设了一个很短的时间,我们可以看到从代码启动到真正定时器触发,代码等待了5秒,就是 time.NewTicker 创建时我们传的参数时间。但如果我们把这个时间改成1个小时,我们需要等待1个小时才会真正开始执行。

寻找解决方案

package main

import (
    "fmt"
    "sync"
    "time"
)

func main() {
    ts := time.NewTicker(5 * time.Second)
    fmt.Println("start_time#", time.Now().Unix())
    var wg sync.WaitGroup
    wg.Add(1)
    go func() {
        for ; true;

上述的执行后返回内容:

start_time# 1656860889
run_time# 1656860889
run_time# 1656860894

我们可以看到首次定时器触发任务的时间变成了程序执行的开始时间!在我们的例子中,这种方式没有问题,但是我们需要关注退出条件,在这里是 main goroutine 直接退出。第一个 goroutine 其实直到 main 退出前一直是堵塞状态。如果你的项目中多次使用这种形式的定时器,每一个都会有一个堵塞的 goroutine,虽然不会对你程序造成 panic,但我还是感觉不是很好。

我的版本

先上代码:

package ticktock

import (
    "time"
)
// 这个结构体内容是为了兼容 Ticker 的使用方式
type tickerStart struct {
    C      chan time.Time
    ticker *time.Ticker
    close  chan struct{}
}

func NewTickerStart(d time.Duration) *tickerStart {
    // 这里我们创建的 channel 设了一个 buffer,原因是我们需要
    // 在下面 Start 方法中及时推送当前时间而不至于堵塞。
    //
    c := make(chan time.Time, 1)
    return &tickerStart{ticker: time.NewTicker(d), C: c, close: make(chan struct{})}
}
// 这是我们核心的方法
func (ts *tickerStart) Start() {
    ts.C

使用代码如下:

package main

import (
    "fmt"
    "sync"
    "time"
    "ticktock"
)

func main() {
    fmt.Println("start_time#", time.Now().Unix())
    chanClose := make(chan struct{})
    tts := ticktock.NewTickerStart(5 * time.Second)
    tts.Start()
    var wg sync.WaitGroup
    wg.Add(1)
    go func() {
        defer wg.Done()
        for {
            select {
            case

执行返回内容如下:

start_time# 1656861872
run_time# 1656861872
run_time# 1656861877

可以看到,和我们想要的一致。但和官方给出的不同我们不会堵塞 goroutine 。

这是我在写虚拟货币账户监控项目中碰到的其中一个问题,我也会在后续的文章中写一写我碰到的其他问题。当然这个项目会开源,可以关注我的 github GanymedeNil’s github

最后的最后

Original: https://www.cnblogs.com/canyuexiang/p/16441444.html
Author: GanymedeNil
Title: 支持首次触发的 Go Ticker

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/516265/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • go 连接MSSQLServer数据库【遇到的坑】

    前言:项目测试需要用到mssqlserver数据库连接,遇到坑,自己爬 直接上代码: go;gutter:true; package main</p> <p&gt…

    Go语言 2023年5月25日
    049
  • Golang通脉之指针

    指针的概念 指针是存储另一个变量的内存地址的变量。 变量是一种使用方便的占位符,用于引用计算机内存地址。 一个指针变量可以指向任何一个值的内存地址。 在上面的图中,变量b的值为15…

    Go语言 2023年5月25日
    061
  • Go语言之结构体与方法

    结构体是一系列属性的集合(类似于 Python 中的类) 1、结构体的定义与使用 // 定义 type Person struct { Name string Age int Se…

    Go语言 2023年5月25日
    062
  • 在浏览器上开发GO和Vue!(基于code-server)

    在浏览器上开发GO和Vue!(基于code-server) 曾几何时,开发者们都被安装编程环境苦恼,尽管现在很多语言的开发环境已经不难装了,但是如果我们能有一个运行在云端的编译器,…

    Go语言 2023年5月25日
    067
  • Go语言之高级篇Beego框架之爬虫项目实战

    一、爬虫项目 1、爬虫基础 a、网页上面会有相同的数据 b、去重处理 布隆过滤器哈希存储 c、标签匹配: 正则表达式beautiful soup或lxml这种标签提取库 d、动态内…

    Go语言 2023年5月29日
    055
  • Go之Logrus用法入门

    Logrus是Go (golang)的结构化日志程序,完全兼容标准库的API日志程序。Logrus is a structured logger for Go (golang), …

    Go语言 2023年5月25日
    060
  • Golang:手撸一个支持六个级别的日志库

    Golang标准日志库提供的日志输出方法有Print、Fatal、Panic等,没有常见的Debug、Info、Error等日志级别,用起来不太顺手。这篇文章就来手撸一个自己的日志…

    Go语言 2023年5月25日
    066
  • go微服务框架Kratos笔记(二)引入zap日志库

    zap日志库是一款高性能的开源日志库,提供了结构化日志记录和printf风格的日志记录 go get -u go.uber.org/zap 参考官方文档中描述,为了方便业务自适配不…

    Go语言 2023年5月25日
    049
  • 十分钟学会Golang开发gRPC服务

    gRPC是Google发起的一个开源RPC框架,使用HTTP/2传输协议,使用Protocol Buffers编码协议,相比RESTful框架的程序性能提高不少,而且当前流行的编程…

    Go语言 2023年5月25日
    070
  • golang低级编程:一.unsafe包

    go语言在设计上确保了一些安全的属性,限制了程序可能出错的途径。例如严格的类型转换规则。但也使得很多实现的细节无法通过go程序来访问,例如对于聚合类型(如结构体)的内存布局,或者一…

    Go语言 2023年5月25日
    043
  • 为开源项目 go-gin-api 增加后台任务模块

    任务管理界面 (WEB) 任务调度器 任务执行器 小结 推荐阅读 任务管理界面 (WEB) 支持在 WEB &#x754C;&#x9762; 中对任务进行管理,例如…

    Go语言 2023年5月25日
    0105
  • strchecker——Go源码字符串规范检查lint工具

    1.背景 在大型项目开发过程中,经常会遇到打印大量日志,输出信息和在源码中写注释的情况。对于软件开发来说,我们一般都是打印输出英文的日志(主要考虑软件在各种环境下的兼容性,如果打印…

    Go语言 2023年5月25日
    041
  • GO的URL合法性检查

    原文连接:https://www.zhoubotong.site/post/67.html Go 标准库的net/url包提供的两个函可以直接检查URL合法性,不需要手动去正则匹配…

    Go语言 2023年5月25日
    078
  • 听说,99% 的 Go 程序员都被 defer 坑过

    先声明:我被坑过。 出问题就对了,这个小东西坏的很,一不留神就出错。 所以,面对这种情况,我们今天就不讲道理了。直接把我珍藏多年的代码一把梭,凭借多年踩坑经历和写 BUG 经验,我…

    Go语言 2023年5月25日
    068
  • AES加解密(golang <--> crypto-js)

    AES(Advanced Encryption Standard) 是一种对称加密算法,是比 DES 更好的对称加密算法类。 使用AES,在前后端之间传送密码等相关数据时,能简单高…

    Go语言 2023年5月25日
    044
  • 基于LSM的Key-Value数据库实现初篇

    前篇文章对LSM的基本原理,算法流程做了简单的介绍,这篇文章将实现一个简单的 基于LSM算法的 迷你Key-Value数据库,结合上篇文章的理论与本篇文章的实践使之对LSM算法有更…

    Go语言 2023年5月25日
    069
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球