首页 > 其他分享 >【go】Go (Golang) 语言-Golang 定时器Timer和Ticker、time.AfterFunc、time.NewTicker()实例

【go】Go (Golang) 语言-Golang 定时器Timer和Ticker、time.AfterFunc、time.NewTicker()实例

时间:2023-12-21 10:36:30浏览次数:42  
标签:NewTicker 定时器 Timer Golang time Ticker AfterFunc

Golang 定时器Timer和Ticker

Golang 定时器包括:一次性定时器(Timer)和周期性定时器(Ticker)。

编程中经常会通过timer和ticker、AfterFunc定时器NewTicker是设定每隔多长时间触发的,是连续触发,而计时器NewTimer是等待多长时间触发的,只触发一次,两者是不同的。等待时间函数AfterFunc是在After基础上加了一个回调函数,是等待时间到来后在另外一个goroutine协程里调用。

Timer

timer创建有两种方式,time.NewTimer(Duration) 和time.After(Duration)。 后者只是对前者的一个包装。
timer到固定时间后会执行一次,请注意是一次,而不是多次。但是可以通过reset来实现每隔固定时间段执行。使用timer定时器,超时后需要重置,才能继续触发。

Ticker

ticker只要定义完成,从此刻开始计时,不需要任何其他的操作,每隔固定时间都会触发。它会以一个间隔(interval)往通道发送当前时间,而通道的接收者可以以固定的时间间隔从通道中读取时间。

time.Timer

首先我们看Timer的结构定义:

type Timer struct {
    C <-chan Time
    r runtimeTimer
}

其中有一个C的只读channel,还有一个runtimeTimer类型的结构体,再看一下这个结构的具体结构:

type runtimeTimer struct {
    tb uintptr
    i  int

    when   int64
    period int64
    f      func(interface{}, uintptr) // NOTE: must not be closure
    arg    interface{}
    seq    uintptr
}

在使用定时timer的时候都是通过 NewTimer 或 AfterFunc 函数来获取。

func NewTimer(d Duration) *Timer {
    c := make(chan Time, 1)
    t := &Timer{
        C: c,
        r: runtimeTimer{
            when: when(d), //表示达到时间段d时候调用f
            f:    sendTime,  // f表示一个函数调用,这里的sendTime表示d时间到达时向Timer.C发送当前的时间
            arg:  c,  // arg表示在调用f的时候把参数arg传递给f,c就是用来接受sendTime发送时间的
        },
    }
    startTimer(&t.r)
    return t
}

定时器的具体实现逻辑,都在 runtime 中的 time.go 中,它的实现,没有采用经典 Unix 间隔定时器 setitimer 系统调用,也没有 采用 POSIX间隔式定时器(相关系统调用:timer_create、timer_settime 和 timer_delete),而是通过四叉树堆(heep)实现的(runtimeTimer 结构中的i字段,表示在堆中的索引)。通过构建一个最小堆,保证最快拿到到期了的定时器执行。定时器的执行,在专门的 goroutine 中进行的:go timerproc()。有兴趣的同学,可以阅读 runtime/time.go 的。

time.NewTimer()实例

package main

import (
    "fmt"

    "time"
)


func main() {
    myTimer := time.NewTimer(time.Second * 2) // 启动定时器
    var i int = 0
    for {
        select {
        case <-myTimer.C:
            i++
            fmt.Println("count: ", i)
            myTimer.Reset(time.Second * 2) // 每次使用完后需要人为重置下
        }
    }

    // 不再使用了,结束它
    myTimer.Stop()
}

使用timer定时器,超时后需要重置,才能继续触发。

time.AfterFunc
Go语言的AfterFunc()函数用于等待经过的时间,此后,它将在其自己的go-routine中调用已定义的函数“f”。此外,此函数在时间包下定义。在这里,您需要导入“time”包才能使用这些函数。

func AfterFunc(d Duration, f func()) *Timer

例子:

// Golang program to illustrate the usage of 
// AfterFunc() function 
  
// Including main package 
package main 
  
// Importing fmt and time 
import ( 
    "fmt"
    "time"
) 
  
// Main function 
func main() { 
  
    // Defining duration parameter of 
    // AfterFunc() method 
    DurationOfTime:= time.Duration(3) * time.Second 
  
    // Defining function parameter of 
    // AfterFunc() method 
    f:= func() { 
  
        // Printed when its called by the 
        // AfterFunc() method in the time 
        // stated above 
        fmt.Println("Function called by "+ 
            "AfterFunc() after 3 seconds") 
    } 
  
    // Calling AfterFunc() method with its 
    // parameter 
    Timer1:= time.AfterFunc(DurationOfTime, f) 
  
    // Calling stop method  
    // w.r.to Timer1 
    defer Timer1.Stop() 
  
    // Calling sleep method 
    time.Sleep(10 * time.Second) 
}

time.Ticker
官网:https://pkg.go.dev/time#NewTicker

Golang time.Timer and time.Ticker
参考URL: https://www.jianshu.com/p/2b4686b8de4a

time.NewTicker()实例
官网:https://pkg.go.dev/time#NewTicker

官方demo

package main

import (
    "fmt"
    "time"
)

func main() {
    ticker := time.NewTicker(time.Second)
    defer ticker.Stop()
    done := make(chan bool)
    go func() {
        time.Sleep(10 * time.Second)
        done <- true
    }()
    for {
        select {
        case <-done:
            fmt.Println("Done!")
            return
        case t := <-ticker.C:
            fmt.Println("Current time: ", t)
        }
    }
}

Ticker是一个周期触发定时的计时器,它会按照一个时间间隔往channel发送系统当前时间,而channel的接收者可以以固定的时间间隔从channel中读取事件。

 

相关函数:

NewTicker() 返回一个新的Ticker,该Ticker包含一个通道字段,并会每隔时间段d就向该通道发送当时的时间。它会调整时间间隔或者丢弃tick信息以适应反应慢的接收者。如果d<=0会panic。关闭该Ticker可以释放相关资源。
Stop() 关闭一个Ticker。在关闭后,将不会发送更多的tick信息。Stop不会关闭通道t.C,以避免从该通道的读取不正确的成功

demo2: time.NewTicker 周期时间到了,但是之前程序没有执行完,怎么处理?

package main

import (
    "fmt"
    "time"
)

func main() {
    ticker := time.NewTicker(time.Second)
    defer ticker.Stop()
    done := make(chan bool)
    go func() {
        time.Sleep(10 * time.Second)
        done <- true
    }()
    for {
        select {
        case <-done:
            fmt.Println("Done!")
            return
        case t := <-ticker.C:
            fmt.Println("Current time: ", t)
            time.Sleep(4 * time.Second)
        }
    }
}

经过代码验证:time.NewTicker定时触发执行任务,当下一次执行到来而当前任务还没有执行结束时,会等待当前任务执行完毕后再执行下一次任务。

[重要]time.NewTicker()使用总结

ticker 创建完之后,不是马上就有一个 tick,第一个 tick 在 x 秒(你自己写的)之后。
Go语言的定时器实质是单向通道,time.Timer结构体类型中有一个time.Time类型的单向chan。
**time.NewTicker定时触发执行任务,当下一次执行到来而当前任务还没有执行结束时,会等待当前任务执行完毕后再执行下一次任务。**查阅go官网的文档和经过代码验证。
t.Stop()在这里并不会停止定时器。这是因为Stop会停止Timer,停止后,Timer不会再被发送,但是Stop不会关闭通道,防止读取通道发生错误。
官方说明:Stop turns off a ticker. After Stop, no more ticks will be sent. Stop does not close the channel, to prevent a concurrent goroutine reading from the channel from seeing an erroneous “tick”.
如果想停止定时器,只能让go程序自动结束。
Ticker 跟 Timer 的不同之处,就在于 Ticker 时间达到后不需要人为调用 Reset 方法,会自动续期。



 

标签:NewTicker,定时器,Timer,Golang,time,Ticker,AfterFunc
From: https://www.cnblogs.com/opensmarty/p/17918416.html

相关文章

  • time 和 hashlib模块
    【一】time模块【1】时间戳importtimeprint(time.time())#1703122154.8660362【2】时间元组本地时间print(time.localtime(time.time()))#time.struct_time(tm_year=2023,tm_mon=12,tm_mday=21,tm_hour=9,tm_min=30,tm_sec=38,tm_wday=3,tm_yday=355,tm_isdst=......
  • Timestamp
    概述Athinwrapperaround<code>java.util.Date</code>thatallowstheJDBCAPItoidentifythisasanSQL<code>TIMESTAMP</code>value.ItaddstheabilitytoholdtheSQL<code>TIMESTAMP</code>fractionalsecondsvalue,......
  • Oracle12c新增max_idle_time参数的学习与感触
    Oracle12c新增max_idle_time参数的学习与感触TLDR其实任何软件出了新版本.readme是很重要的.尤其是数据库,涉及到底层问题的.比如这次遇到的Oracle的max_idle_time参数,以及前几天遇到的Mysql的新增的parallel关键字.自己之前的积累可能是一盏明灯,也可能是一堵墙.......
  • 初中英语优秀范文100篇-033My Free Time-我的业余时间
    PDF格式公众号回复关键字:SHCZFW033记忆树1Ihavealotofthingstodoinmyfreetime.翻译我有很多空闲时间要做的事情。简化记忆事情句子结构主语(I):表示句子中的主体,即说话者本人。谓语(have):表示主体所进行的动作或状态,这里是“有”的意思。宾语(alotofthing......
  • TimeZone
    概述<code>TimeZone</code>representsatimezoneoffset,andalsofiguresoutdaylightsavings.Typically,yougeta<code>TimeZone</code>using<code>getDefault</code>whichcreatesa<code>TimeZone</code>b......
  • datetime模块
    datetime模块(1)导入模块importdatetime(2)自定义日期并格式化datetime.date()自定义日期并格式化##2.自定义日期并格式化#res=datetime.date(2023,8,18)#print(res)##2023-08-18(3)获取本地时间datetime.date.today()获取年月日##(1)年月日#now_date=datetime.......
  • Derivative norm vector repect to time 《PBM by Pixar》 Appendix D.2 code
    目录1Derivativenormalvectorrepecttotime1.1DerivativevectornormrepecttotimeXRefVectorCalculus1DerivativenormalvectorrepecttotimeLet'sdenotetheunitnormalvectoras:\[\mathbf{n}=\frac{\mathbf{e}_a\times\mathbf{e}_b}{......
  • time模块
    time模块表示时间的三种方式时间戳元组(struct_time)格式化的时间字符串:格式化的时间字符串(FormatString):‘1999-12-06’(1)导入模块importtime(2)时间戳(time)(1)生成时间戳生成时间戳,时间戳是浮点数类型##时间戳##time=time.time()##print(time)......
  • golang快速入门:结构体
    结构体Go语言的面向对象编程与我们之前所熟悉的PHP、Java那一套完全不同,没有 class、extends、implements 之类的关键字和相应的概念,而是借助结构体来实现类的声明。typePersonstruct{namestring//名字malebool//性别}可以理解为类名 Person,并且包含了 ......
  • 高德地图api报错 Get geolocation timeout.Get ipLocation failed.
    使用了https报错Getgeolocationtimeout.GetipLocationfailed. 报错是定位超时,由于JSAPI使用的是浏览器提供的定位服务,所以定位的准确度和成功率都会对浏览器有很大的依赖。由于Chrome在国内没有提供服务,因此使用Chrome定位服务的浏览器,比如:Chrome、火狐、安卓原生WebVie......