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 相关文章推荐
golang中的空slice案例
Apr 27 Golang
Golang 实现超大文件读取的两种方法
Apr 27 Golang
golang http使用踩过的坑与填坑指南
Apr 27 Golang
golang 接口嵌套实现复用的操作
Apr 29 Golang
Golang中interface{}转为数组的操作
Apr 30 Golang
go设置多个GOPATH的方式
May 05 Golang
golang 语言中错误处理机制
Aug 30 Golang
Golang Elasticsearches 批量修改查询及发送MQ
Apr 19 Golang
Golang 切片(Slice)实现增删改查
Apr 22 Golang
GoFrame框架数据校验之校验结果Error接口对象
Jun 21 Golang
Go结合Gin导出Mysql数据到Excel表格
Aug 05 Golang
Go中使用gjson来操作JSON数据的实现
Aug 14 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代码优化之成员变量获取速度对比
2014/02/28 PHP
java微信开发之上传下载多媒体文件
2016/06/24 PHP
PHP+Redis开发的书签案例实战详解
2019/07/09 PHP
PHP 自动加载类原理与用法实例分析
2020/04/14 PHP
Js+XML 操作
2006/09/20 Javascript
JavaScript计时器示例分析
2015/02/05 Javascript
JS实现兼容性好,带缓冲的动感网页右键菜单效果
2015/09/18 Javascript
JavaScript、tab切换完整版(自动切换、鼠标移入停止、移开运行)
2016/01/05 Javascript
jQuery实现百度登录框的动态切换效果
2017/04/21 jQuery
用户管理的设计_jquery的ajax实现二级联动效果
2017/07/13 jQuery
[js高手之路]从原型链开始图解继承到组合继承的产生详解
2017/08/28 Javascript
vue+vuex+axios+echarts画一个动态更新的中国地图的方法
2017/12/19 Javascript
JS实现的将html转为pdf功能【基于浏览器端插件jsPDF】
2018/02/06 Javascript
vue 自定义组件的写法与用法详解
2020/03/04 Javascript
微信小程序实现比较功能的方法汇总(五种方法)
2020/03/07 Javascript
在vue中对数组值变化的监听与重新响应渲染操作
2020/07/17 Javascript
JavaScript实现点击切换验证码及校验
2021/01/10 Javascript
python中的一些类型转换函数小结
2013/02/10 Python
Python实现3行代码解简单的一元一次方程
2014/08/18 Python
python获得linux下所有挂载点(mount points)的方法
2015/04/29 Python
django通过ajax发起请求返回JSON格式数据的方法
2015/06/04 Python
python操作redis的方法
2015/07/07 Python
基于Python的微信机器人开发 微信登录和获取好友列表实现解析
2019/08/21 Python
用python实现英文字母和相应序数转换的方法
2019/09/18 Python
Python全局锁中如何合理运用多线程(多进程)
2019/11/06 Python
python 浅谈serial与stm32通信的编码问题
2019/12/18 Python
解决python -m pip install --upgrade pip 升级不成功问题
2020/03/05 Python
python实现输入三角形边长自动作图求面积案例
2020/04/12 Python
Python 如何实现访问者模式
2020/07/28 Python
中国一家专注拼团的社交购物网站:拼多多
2018/06/13 全球购物
Coccinelle官网:意大利的著名皮具品牌
2019/05/15 全球购物
物业管理个人自我评价
2013/11/08 职场文书
创文明城市标语
2014/06/16 职场文书
见习期个人总结
2015/03/05 职场文书
2016党校培训心得体会
2016/01/07 职场文书
Python内置类型集合set和frozenset的使用详解
2022/04/26 Python