计时器的生命周期 | 青训营笔记

简介: 计时器的生命周期 | 青训营笔记

前言

全文基于GO 1.14计时器在定时执行一些任务时很有用。Go内部依靠调度器来管理创建的计时器。而Go的调度程序是协作式的调度方式,这会让整个调度看起来比较复杂,因为goroutune必须自己停止(依赖channel阻塞或system call), 或者由调度器自己在某个调度点暂停。

有关抢占的更多信息,建议您阅读作者的文章Go: Goroutine and Preemption.

生命周期

下面是一段简单示例代码:

func main(){
  sigs := make(chan os.Signal,1)
  signal.Notify(sigs,syscall.SIGINT,syscall.SIGTERM)
  time.AfterFunc(time.Second, func() {
    println("done")
  })
  <- sigs
}

计时器创建后,他会保存到一个链接到当前P的计时器内部列表上,下图就是这段代码的表示形式:

image.png

有关G,M,P模型的更多信息,建议您阅读作者的文章Go: Goroutine, OS Thread and CPU Management

从图中可以看到,一旦创建了计时器,它就会注册一个内部回调,该内部回调将使用go回调用户函数,并将其转换为goroutine。

然后,将通过调度程序管理计时器。在每一轮调度中,它都会检查计时器是否准备好运行,如果准备就绪,则准备运行。实际上,由于Go调度程序本身不会运行任何代码,因此运行计时器的回调会将其goroutine排队到本地队列中。然后,当调度程序在队列中将其接收时,goroutine将运行。如选图所示:

image.png

根据本地队列的大小,计时器运行可能会稍有延迟。不过,由于Go 1.14中的异步抢占,goroutines在运行时间10ms后会被抢占,降低了延迟的可能性。

延迟

为了了解计时器可能存在的延迟,我们创造一个场景:从同一goroutine创建大量计时器。

由于计时器都链接到当前P,因此繁忙的P无法及时运行其链接的计时器。代码如下:

func main(){
  trace.Start(os.Stderr)
  defer trace.Stop()
  sigs := make(chan os.Signal,1)
  signal.Notify(sigs,syscall.SIGINT,syscall.SIGTERM)
  //time.AfterFunc(time.Second, func() {
  //  println("done")
  //})
  var num int64
  for i:=0; i< 1e3 ; i++ {
    time.AfterFunc(time.Second, func() {
      atomic.AddInt64(&num,1)
    })
  }
  t:= 0
  for i:=0;i<1e10; i++ {
    t ++
  }
  _ = t
  <- sigs
  println(num,"timers created,",t,"iterations done")
}

通过go tool trace, 我们可以看到goroutine正在占用处理器:

image.png

由于异步抢占的原因,代表正在运行的goroutine图形被分成了大量较小的块。

在这些块中,一个空间看起来比其他空间大。让我们放大一下:

image.png

在该计时器需要运行时,就会发生改情况。此时,当前goroutine已被Go调度程序抢占和取代。调度程序将计时器转换为可运行的goroutine,如图所示。

但是,当前线程的Go调度程序并不是唯一运行计时器的调度程序。Go实施了一种计时器窃取策略,以确保在当前P繁忙时可以由另一个P运行计时器。由于异步抢占,它不太可能发生,但是在我们的示例中,由于使用了大量的计时器,它发生了。如下图所示:

image.png

如果我们不考虑计时器窃取,将发生以下情况:

image.png

持有计时器的所有goroutine都会添加到本地队列中。然后,由于 P之间的窃取,将准确的调度计时器。

所以,由于异步抢占和工作窃取,延迟几乎不可能发生。


目录
相关文章
|
设计模式 Java uml
C++设计模式之 依赖注入模式探索
C++设计模式之 依赖注入模式探索
673 0
|
存储 开发者
国标GB28181协议客户端开发(二)程序架构和注册
国标GB28181协议客户端开发(二)程序架构和注册
1256 0
|
网络协议
udhcpc 参数使用说明
当没有网络的时候,板子一直发送dhcp请求,导致程序不往下执行,解决的办法是把它切换到后台运行,可是如何切换到后台呢,有办法,它自带参数可以实现该功能。如下:   udhcpc -b -i eth0 -p /var/run/udhcpc.pid -R解释一下,-b就是切换到后台指令,-i是指定使用哪个网络接口,双网卡的时候一定要使用它来指定eth0  or  eth1。
2767 0
|
存储 编解码 算法
深入浅出:FFmpeg 音频解码与处理AVFrame全解析(一)
深入浅出:FFmpeg 音频解码与处理AVFrame全解析
2166 0
|
物联网 数据安全/隐私保护
理解OAuth 2.0并实现一个客户端 | 青训营笔记(上)
理解OAuth 2.0并实现一个客户端 | 青训营笔记(上)
320 0
|
机器学习/深度学习
基于RTP的H264视频数据打包解包类
from:http://blog.csdn.net/dengzikun/article/details/5807694 最近考虑使用RTP替换原有的高清视频传输协议,遂上网查找有关H264视频RTP打包、解包的文档和代码。
2009 0
|
XML 网络协议 Android开发
linphone源码分析----初始化部分
<span style="color:rgb(51,51,51); font-family:'Helvetica Neue',Helvetica,Tahoma,Arial,STXihei,'Microsoft YaHei',微软雅黑,sans-serif; font-size:16px; line-height:28.799999237060547px">这几天比较轻松,所以打算好好来看看
2944 0
|
6天前
|
云安全 监控 安全
|
3天前
|
存储 机器学习/深度学习 人工智能
打破硬件壁垒!煎饺App:强悍AI语音工具,为何是豆包AI手机平替?
直接上干货!3000 字以上长文,细节拉满,把核心功能、使用技巧和实测结论全给大家摆明白,读完你就知道这款 “安卓机通用 AI 语音工具"——煎饺App它为何能打破硬件壁垒?它接下来,咱们就深度拆解煎饺 App—— 先给大家扒清楚它的使用逻辑,附上“操作演示”和“🚀快速上手不踩坑 : 4 条核心操作干货(必看)”,跟着走零基础也能快速上手;后续再用真实实测数据,正面硬刚煎饺 App的语音助手口令效果——创建京东「牛奶自动下单神器」口令 ,从修改口令、识别准确率到场景实用性,逐一测试不掺水,最后,再和豆包 AI 手机语音助手的普通版——豆包App对比测试下,简单地谈谈煎饺App的能力边界在哪?