golang 定时任务方面time.Sleep和time.Tick的优劣对比
目录
golang 写循环执行的定时任务,常见的有以下三种实现方式:
这三种定时器的实现原理
优劣性对比,使用建议
golang 写循环执行的定时任务,常见的有以下三种实现方式:
1、time.Sleep方法:
|
2、time.Tick函数:
|
3、其中Tick定时任务,也可以先使用time.Ticker函数获取Ticker结构体,然后进行阻塞监听信息,这种方式可以手动选择停止定时任务,在停止任务时,减少对内存的浪费。
|
其中第二种和第三种可以归为同一类
这三种定时器的实现原理
一般来说,你在使用执行定时任务的时候,一般旁人会劝你不要使用time.Sleep完成定时任务,但是为什么不能使用Sleep函数完成定时任务呢,它和Tick函数比,有什么劣势呢?这就需要我们去探讨阅读一下源码,分析一下它们之间的优劣性。
首先,我们研究一下Tick函数,func Tick(d Duration) <-chan Time
调用Tick函数会返回一个时间类型的channel,如果对channel稍微有些了解的话,我们首先会想到,既然是返回一个channel,在调用Tick方法的过程中,必然创建了goroutine,该Goroutine负责发送数据,唤醒被阻塞的定时任务。我在阅读源码之后,确实发现函数中go出去了一个协程,处理定时任务。
按照当前的理解,使用一个tick,需要go出去一个协程,效率和对内存空间的占用肯定不能比sleep函数强。我们需要继续阅读源码才拿获取到真理。
简单的调用过程我就不陈述了,我在这介绍一下核心结构体和方法(删除了部分判断代码,解释我写在表格中):
|
timersBucket,顾名思义,时间任务桶,是外界不可见的全局变量。每当有新的timer定时器任务时,会将timer加入到timersBucket中的timer切片。timerBucket结构体如下:
|
func timerproc(tb *timersBucket) 详细介绍
可以称之为定时任务处理器,所有的定时任务都会加入timersBucket,然后在该函数中等待被处理。等待被处理的timer,根据when字段(任务执行的时间,int类型,纳秒级别)构成一个最小堆,每次处理完成堆顶的某个timer时,会给它的when字段加上定时任务循环间隔时间(即Tick(d Duration) 中的d参数),然后重新维护堆,保证when最小的timer在堆顶。当堆中没有可以处理的timer(有timer,但是还不到执行时间),需要计算当前时间和堆顶中timer的任务执行时间差值delta,定时任务处理器沉睡delta段时间,等待被调度器唤醒。核心代码如下(注释写在每行代码的后面,删除一些判断代码以及不利于阅读的非核心代码):
|
至此,time.Tick函数涉及到的主要功能就讲解结束了,总结一下就是启动定时任务时,会创建一个唯一协程,处理timer,所有的timer都在该协程中处理。
然后,我们再阅读一下sleep的源码实现,核心源码如下:
|
读了sleep的核心代码之后,是不是突然发现和Tick函数的内容很类似,都创建了timer,并加入了定时任务处理协程。神奇之处就在于,实际上这两个函数产生的timer都放入了同一个timer堆,都在定时任务处理协程中等待被处理。
优劣性对比,使用建议
现在我们知道了,Tick,Sleep,包括time.After函数,都使用的timer结构体,都会被放在同一个协程中统一处理,这样看起来使用Tick,Sleep并没有什么区别。
实际上是有区别的,Sleep是使用睡眠完成定时任务,需要被调度唤醒。Tick函数是使用channel阻塞当前协程,完成定时任务的执行。当前并不清楚golang 阻塞和睡眠对资源的消耗会有什么区别,这方面不能给出建议。
但是使用channel阻塞协程完成定时任务比较灵活,可以结合select设置超时时间以及默认执行方法,而且可以设置timer的主动关闭,以及不需要每次都生成一个timer(这方面节省系统内存,垃圾收回也需要时间)。
所以,建议使用time.Tick完成定时任务。
golang 定时任务方面time.Sleep和time.Tick的优劣对比相关推荐
- golang定时任务的使用
golang定时任务的使用 由于 golang 标准库内没有比较好的定时任务包,所以这里将使用一个第三方的 cron 包,由于此包存在一些不适用的地方,所以对此做了一些简单封装. cron简介 rob ...
- Golang 定时任务 github/robfig/cron/v3 使用与源码解析
Cron 源码阅读 robfig/cron/v3 是一个 Golang 的定时任务库,支持 cron 表达式.Cron 的源码真实教科书级别的存在(可能是我菜 -),真的把低耦合高内聚体现地淋漓尽致, ...
- 从Golang调度器的作者视角探究其设计之道!
导语 | Golang核心开发人员.goroutine调度的设计者Dmitry Vyukov,在2019年的一个talk里深入浅出地阐述了goroutine调度的设计思想以及一些优化的细节.本文是笔者 ...
- 实现了一个golang周期任务调度包
drumstick Implement crond by Golang https://github.com/openex27/drumstick 鼓槌(鸡腿),golang定时任务包 功能特性: 1 ...
- Let‘s Go Rust 系列之定时器 Ticker Timer
前言 在实际项目开发中,经常会有定时任务的功能开发需求,定时任务主要分为两种, 1,在固定的时刻执行某个任务,也就是 Timer 2,基于固定的时间间隔,周期的执行某个任务,也就是Ticker 很 ...
- Game as a Service —— 开源云游戏搭载WebRTC
软件即服务,基础架构即服务,平台即服务,通信平台即服务,视频会议即服务,那么,游戏即服务(Game as a Service)如何呢?已经有不少科技公司试水云游戏,最著名的要数Google的Stadi ...
- Netty系列之Netty线程模型
关注点在于:如何灵活的动态绑定IO事件处理,又能进行串行化处理减少锁的使用 摘自:http://www.infoq.com/cn/articles/netty-threading-model 1. 背 ...
- zabbix二次开发之从mysql取值在运维平台js图表展现
前沿: 集群控制平台已经要慢慢的灰度上线了,出问题的时候,才找点bug,时间有点空闲.正好看了下zabbix的数据库,产生了自己想做一套能更好的展现zabbix的页面. 更多内容请到我的个人的博客站点 ...
- 那些在一个公司死磕5-10年的人,最后都怎么样了...
很多人都不了解,JVM中的对象是可以进行栈上分配和TLAB(线程本地分配)的,看我用动画给你演示这个过程! 不光深入,而且生动,用最鲜活的展现手段让你进行轻松的提升. 细想想现在互联网大厂中,面对JV ...
最新文章
- 行业洞察驱动安全防御严峻安全挑战迎刃而解
- python中如何将字符串连接在一起,多倍的字符串如何输出
- 记录 之 在华为NPU上变更镜像
- 前后落差大用什么词语_形容落差很大的成语_四字词语 - 成梦词典
- Java入门系列-20-异常
- spring cloud bus_Spring Cloud学习笔记--消息总线(Bus)
- 新rust怎么拆除围墙_“问题围挡”拆除 街道变漂亮了
- 转 8天入门wpf—— 第六天 细说控件
- OLAP-druid-大数据Week13-DAY2-druid
- 建模步骤_带你十个步骤学建模(二)
- love~LBJ,奥布莱恩神杯3
- [UOJ#132][BZOJ4200][luogu_P2304][NOI2015]小园丁与老司机
- xcode 免cleanup build
- macOS Big Sur 11.2.2 (20D80) 虚拟机 ISO 镜像
- 为什么这么多人怼我?或许是这个原因
- HTML播放华为云视频流,华为云点播服务视频管理功能强大,上云就是省心
- 以窗口形式进行数字图像处理时,在图像边界处对超出图像边界的窗口内容的映射(对称)处理
- to be top。。。
- 用网盘(dropbox,kuaipan,everbox)保管的git repository
- java entry getvalue_Java Entry.getValue方法代碼示例