Golang入门之计时器


Posted in Golang onMay 04, 2022

引言

一般来说,很多时候我们面临这样一种情况,即我们需要运行时间记录器,它不断向我们显示当前时间或在给定的时间间隔内保持执行一定的代码和平,在这种情况下,我们应该使用 ​​Ticker​​​,使用这个我们需要使用 go 语言的 ​​time​​​ 包,我们有一个名为 ​​NewTicker()​​​ 的方法,它允许我们停止和启动时间代码,我们需要通过传递 ​​chan​​​ 和 ​​bool​​ 作为将使用的参数来创建一个代码通道检查它是否打开,如果通道打开意味着计时器将继续。

Go 的计时器

Go 提供了非常简单的语法来实现一个计时器,定时器的结构体定义:

type Ticker struct {
C <-chan Time // 抛出来的channel,给上层系统使用,实现计时
r runtimeTimer // 给系统管理使用的定时器,系统通过该字段确定定时器是否到时,如果到时,调用对应的函数向C中推送当前时间。
}

Ticker对外仅暴露一个 channel,指定的时间到来时就往该 channel 中写入系统时间,也即一个事件。

Ticker 的使用方式也很简单,代码如下:

import time
TimeTicker := time.NewTicker(1 * time.Second)
TimeTicker.Stop()
  • ​time​​​ : 如果想要使用​​time​​ 中的计时器,那么需要将其导入代码中
  • ​NewTicker()​​​ 函数:这个很好理解,新建一个计时器,然后该计时器以时间表达式作为参数,比如一秒​​1*time.Second​​​ ,而不是直接传入​​1​​​ ,也可以传入其他时间方式,比如​​2*time.Millisecond​
  • 最后,我们可以使用时间表达式调用由​​NewTicker​​​ 函数创建的变量上的任何活动。例如,在上面的语法中,我们使用了​​TimeTicker.Stop()​​​ 来停止时间计时器。我们可以在特定条件下使用它,比如定义倒数 10 秒的计时器,就可以检查时间是否满足 10 秒,一旦 10 秒发生,我们可以调用​​TimeTicker.stop()​​。

我们可以每隔一秒输出一个结果,比如实现一个倒数 10 个数的功能:

package main
import (
"fmt"
"time"
)
func main() {
TimeTicker := time.NewTicker(1 * time.Second)
i := 10
for {
<-TimeTicker.C
fmt.Println("i = ", i)
i--
if i == 0 {
TimeTicker.Stop()
break
}
}
}

然后执行该程序:

$ go run main.go
i = 10
i = 9
i = 8
i = 7
i = 6
i = 5
i = 4
i = 3
i = 2
i = 1

Ticker 计时器是如何工作的?

​NewTicker​​​创建的计时器与​​NewTimer​​​创建的计时器持有的时间​​channel​​​一样都是带一个缓存的​​channel​​​,每次触发后执行的函数也是​​sendTime​​​,这样即保证了无论有误接收方​​Ticker​​触发时间事件时都不会阻塞:

func NewTicker(d Duration) *Ticker {
if d <= 0 {
panic(errors.New("non-positive interval for NewTicker"))
}
// Give the channel a 1-element time buffer.
// If the client falls behind while reading, we drop ticks
// on the floor until the client catches up.
c := make(chan Time, 1)
t := &Ticker{
C: c,
r: runtimeTimer{
when: when(d),
period: int64(d),
f: sendTime,
arg: c,
},
}
startTimer(&t.r)
return t
}

NewTicker()只是构造了一个Ticker,然后把Ticker.r通过startTimer()交给系统协程维护。

其中period为事件触发的周期。

其中​​sendTime()​​方法便是定时器触发时的动作:

func sendTime(c interface{}, seq uintptr) {
select {
case c.(chan Time) <- Now():
default:
}
}

​sendTime​​ 接收一个管道作为参数,其主要任务是向管道中写入当前时间。

停止Ticker:

停止Ticker,只是简单的把Ticker从系统协程中移除。

函数主要实现如下:

func (t *Ticker) Stop() {
stopTimer(&t.r)
}

​stopTicker()​​ 即通知系统协程把该 Ticker 移除,即不再监控。系统协程只是移除 Ticker 并不会关闭管道,以避免用户协程读取错误。

Ticker 使用方式

例子一:

package main
import (
"fmt"
"time"
)
func main() {
TimeTicker := time.NewTicker(3 * time.Second)
tickerChannel := make(chan bool)
go func() {
for {
select {
case timeticker := <-TimeTicker.C:
fmt.Println("The time for current is : ", timeticker)
case <-tickerChannel:
return
}
}
}()
time.Sleep(6 * time.Second)
TimeTicker.Stop()
tickerChannel <- true
fmt.Println("Time for running ticker is completed")
}

运行该代码:

$ go run main.go
The time for current is : 2022-04-29 22:37:13.93862 +0800 CST m=+3.000267823
The time for current is : 2022-04-29 22:37:16.939081 +0800 CST m=+6.000707515
Time for running ticker is completed

例子二:

package main
import (
"fmt"
"time"
)
func main() {
tm := time.Millisecond
tickerTicker := time.NewTicker(400 * tm)
tickerChaneel := make(chan bool)
go func() {
for {
select {
case <-tickerChaneel:
return
case tmtr := <-tickerTicker.C:
fmt.Println("Ticker time at current is", tmtr)
}
}
}()
time.Sleep(1400 * time.Millisecond)
tickerTicker.Stop()
tickerChaneel <- true
fmt.Println("Ticker has stopped now")
}

运行该代码:

$ go run main.go
Ticker time at current is 2022-04-29 22:39:51.13057 +0800 CST m=+0.400159916
Ticker time at current is 2022-04-29 22:39:51.531516 +0800 CST m=+0.801102997
Ticker time at current is 2022-04-29 22:39:51.931238 +0800 CST m=+1.200822301
Ticker has stopped now

总结

本文简单了解了 go 计时器 ​​Ticker​​​ 的基本概念,介绍了它的工作原理,并且我们专注于 go 语言中 ​​ticker​​ 的语法和使用。最后展现了 go 语言中的一些重要示例。

到此这篇关于Golang入门之计时器介绍的文章就介绍到这了!


Tags in this post...

Golang 相关文章推荐
Go语言中的UTF-8实现
Apr 26 Golang
golang DNS服务器的简单实现操作
Apr 30 Golang
Go 在 MongoDB 中常用查询与修改的操作
May 07 Golang
关于golang高并发的实现与注意事项说明
May 08 Golang
Golang标准库syscall详解(什么是系统调用)
May 25 Golang
golang中字符串MD5生成方式总结
Jul 04 Golang
golang内置函数len的小技巧
Jul 25 Golang
golang三种设计模式之简单工厂、方法工厂和抽象工厂
Apr 10 Golang
golang用type-switch判断interface的实际存储类型
Apr 14 Golang
Golang获取List列表元素的四种方式
Apr 20 Golang
Go获取两个时区的时间差
Apr 20 Golang
Go语言测试库testify使用学习
Jul 23 Golang
Golang 入门 之url 包
May 04 #Golang
Golang解析JSON对象
Apr 30 #Golang
Golang 并发编程 SingleFlight模式
Golang 实现 WebSockets 之创建 WebSockets
Apr 24 #Golang
Golang 实现WebSockets
Golang ort 中的sortInts 方法
Apr 24 #Golang
Golang 切片(Slice)实现增删改查
Apr 22 #Golang
You might like
PHP类与对象中的private访问控制的疑问
2012/11/01 PHP
php强制文件下载而非在浏览器打开的自定义函数分享
2014/05/08 PHP
浅谈PHP中的错误处理和异常处理
2017/02/04 PHP
tp5(thinkPHP5框架)使用DB实现批量删除功能示例
2019/05/28 PHP
页面中js执行顺序
2009/11/09 Javascript
利用jquery操作select下拉列表框的代码
2010/06/04 Javascript
JQuery勾选指定name的复选框集合并显示的方法
2015/05/18 Javascript
纯CSS3代码实现滑动开关效果
2015/08/19 Javascript
javascript中的五种基本数据类型
2015/08/26 Javascript
基于JQuery和CSS3实现仿Apple TV海报背景视觉差特效源码分享
2015/09/21 Javascript
IScroll5 中文API参数说明和调用方法
2016/05/21 Javascript
JS实现添加,替换,删除节点元素的方法
2016/06/30 Javascript
详解XMLHttpRequest(一)同步请求和异步请求
2016/09/14 Javascript
js仿QQ邮箱收件人选择与搜索功能
2017/02/10 Javascript
React-Native做一个文本输入框组件的实现代码
2017/08/10 Javascript
seajs中最常用的7个功能、配置示例
2017/10/10 Javascript
详解webpack import()动态加载模块踩坑
2018/07/17 Javascript
JS实现可视化文件上传
2018/09/08 Javascript
JS为什么说async/await是generator的语法糖详解
2019/07/11 Javascript
Js参数RSA加密传输之jsencrypt.js的使用
2020/02/07 Javascript
Python实现的多线程端口扫描工具分享
2015/01/21 Python
举例简单讲解Python中的数据存储模块shelve的用法
2016/03/03 Python
基于python OpenCV实现动态人脸检测
2018/05/25 Python
Python subprocess模块常见用法分析
2018/06/12 Python
TensorFlow的权值更新方法
2018/06/14 Python
Python数据分析:手把手教你用Pandas生成可视化图表的教程
2018/12/15 Python
解决python3中的requests解析中文页面出现乱码问题
2019/04/19 Python
Python Numpy 控制台完全输出ndarray的实现
2020/02/19 Python
Python函数默认参数常见问题及解决方案
2020/03/26 Python
澳大利亚男士西服品牌:M.J.Bale
2018/02/06 全球购物
法律进企业活动方案
2014/03/04 职场文书
体育课外活动总结
2014/07/08 职场文书
大专护理专业自荐信
2015/03/25 职场文书
建国大业电影观后感
2015/06/01 职场文书
2016年推广普通话宣传周活动总结
2016/04/06 职场文书
Spring boot admin 服务监控利器详解
2022/08/05 Java/Android