Golang当中的定时器

news2024/11/19 15:13:22

定时器

  • 前言
  • 定时器的基本使用

前言

在平时写代码的时候,我们经常会遇到在将来某个时间点或者间隔一段时间重复执行函数。这个时候我们就可以考虑使用定时器。本片文章主要介绍一下golang当中的几个常用的定时器。time.Timer,time.Ticker,time.After以及time.AfterFunctime.Ticker的基本使用

定时器的基本使用

golang当中的定时器有这个一次性的定时器(Timer)和周期性的定时器(Ticker).在平时的编程当中经常会使用timer当中的ticker,AfterFunc定时器,而NewTicker是每隔多长时间触发,NewTimer是等待多长时间触发一次请注意是只触发一次。请注意一下两者的区别。
下面我们来首先来使用一下这两个定时器首先是这个Timer定时器

package main

import (
	"fmt"
	"time"
)
func main() {
	myTimer := time.NewTimer(time.Second * 3) //初始化定时器
	var i = 0
	for {
		select {
		case <-myTimer.C:
			i++
			fmt.Printf("the counter is%d", i)
			myTimer.Reset(time.Second * 3) //注意需要重新设置
		}
	}
	myTimer.Stop() //不在使用需要将其停止
}

注意这个timer定时器超时之后需要重新进行设置,才能重新触发。如果上面的代码我们没有Reset,那么就会导致死锁。其实我们也可以看看这个Timer是怎么是实现的

func NewTimer(d Duration) *Timer {
    c := make(chan Time, 1)
    t := &Timer{
        C: c,  // 信道
        r: runtimeTimer{
            when: when(d),  // 触发时间
            f:    sendTime, // 时间到了之后的调用函数
            arg:  c,        // 调用sendTime时的入参
        },
    }
    startTimer(&t.r)  // 把定时器的r字段放入由定时器维护协程维护的堆中
    return t
} 

从上面的构造函数中可以大概看出定时器的工作流程,这里面最重要的是runtimeTimer。构造定时器的时候会把runtimeTimer放入由定时器维护协程维护的堆中,当时间到了之后,维护协程把r从堆中移除,并调用r的sendTime函数,sendTime的入参是定时器的信道C。可以推断,sendTime中执行的逻辑应该是向信道C中推送时间,通知上游系统时间到了,而事实正是如此:

func sendTime(c interface{}, seq uintptr) {
    // Non-blocking send of time on c.
    // Used in NewTimer, it cannot block anyway (buffer).
    // Used in NewTicker, dropping sends on the floor is
    // the desired behavior when the reader gets behind,
    // because the sends are periodic.
    select {
    case c.(chan Time) <- Now():  //时间到了之后把当前时间放入信道中
    default:
    }
} 

其实这个time.After就是对这个time.Timer的一个封装,所以如果我们上面使用这个time.After那么会频繁的创建time.Timer对象
下面我们在来看一下这个time.AterFunc()定时器。
Golang当中的AfterFunc函数用于等待经过时间,此后在其自己的协程当中调用定义的函数f.函数在时间包下定义。下面我们一起看看如何使用这个

import (
	"fmt"
	"time"
)

func main() {
	f := func() {
		fmt.Println("the func is call after 3 second")
	}
	myTime := time.AfterFunc(time.Second*3, f)

	defer myTime.Stop() //定时器不用了需要关闭
	time.Sleep(time.Second * 4)
}

下面我们在看看这个time.NewTicker定时器的使用

package main

import (
	"fmt"
	"time"
)

func main() {
	mytick := time.NewTicker(time.Second * 2)
	defer mytick.Stop() //定时器不用了需要关闭
	done := make(chan struct{})
	go func() {
		for {
			time.Sleep(time.Second * 10)
			done <- struct{}{}
		}
	}()
	for {
		select {
		case <-done:
			fmt.Println("done!!!!")
			return
		case t := <-mytick.C:
			fmt.Printf("the curtime is %v\n", t)
		}
	}

}

下面我们来看一下这个陷阱,这个需要注意

package main

import (
	"fmt"
	"time"
)
func main() {
	var count int
	for {
		select {
		case <-time.Tick(time.Second * 1):
			fmt.Println("case1")
			count++
			fmt.Println("count--->", count)
		case <-time.Tick(time.Second * 2):
			fmt.Println("case2")
			count++
			fmt.Println("count--->", count)
		}
	}
	
}

这个代码是有陷阱的,下面我们来看看这个运行结果是什么?
在这里插入图片描述
可见 case2 永远没有被执行到,问题就出在代码逻辑上,首先看time.Tick方法。我们可以看一下这个方法就知道

func Tick(d Duration) <-chan Time {
	if d <= 0 {
		return nil
	}
	return NewTicker(d).C
}

它每次都会创建一个新的定时器,随着 for 循环进行, select 始终监听两个新创建的定时器,老的定时器被抛弃掉了,也就不会去读取老定时器中的通道。
select 可以同时监听多个通道,谁先到达就先读取谁,如果同时有多个通道有消息到达,那么会随机读取一个通道,其他的通道由于没有被读取,所以数据不会丢失,需要循环调用 select 来读取剩下的通道。

总结:

  • tick创建完成之后,不是马上有一个tick.第一个tick在你设置的多少秒之后才会进行创建
  • golang当中的定时器实质上是这个单项的管道
  • time.NewTicker会定时触发任务,当下一次执行到来而当前任务画面执行完,会等待当前任务执行完毕在进行下一次任务。
  • Ticker和Timer的不同之处是,Ticker时间到达之后不需要人为的调用Reset方法来重新设置时间

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/492173.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

文鼎创智能物联云原生容器化平台实践

作者&#xff1a;sekfung&#xff0c;深圳市文鼎创数据科技有限公司研发工程师&#xff0c;负责公司物联网终端平台的开发&#xff0c;稳定性建设&#xff0c;容器化上云工作&#xff0c;擅长使用 GO、Java 开发分布式系统&#xff0c;持续关注分布式&#xff0c;云原生等前沿技…

《安富莱嵌入式周报》第311期:300V可调节全隔离USB PD电源,开源交流负载分析仪,CANFD Trace,6位半多斜率精密ADC设计,开源数学库

周报汇总地址&#xff1a;嵌入式周报 - uCOS & uCGUI & emWin & embOS & TouchGFX & ThreadX - 硬汉嵌入式论坛 - Powered by Discuz! 视频版&#xff1a; https://www.bilibili.com/video/BV1Hh4y1H7dR 《安富莱嵌入式周报》第311期&#xff1a;300V可调…

【机器学习】决策树算法解读

【机器学习】决策树算法解读 文章目录 【机器学习】决策树算法解读1. 介绍1.1 优缺点1.2 结构1.3 学习过程1.4 决策树与条件概率分布 2. 决策树学习过程2.1 训练策略2.2 特征选择2.2.1 信息增益和条件熵 2.3 决策树的生成2.3.1 ID32.3.2 C4.52.3.3 CART2.3.4 小结 2.4 决策树的…

Nacos配置中心、配置热更新、及配置共享的记录

Nacos除了提供了注册中心的功能,同样也提供了配置中心的功能,用于管理一些叫常改动的配置 当微服务部署的实例越来越多&#xff0c;达到数十、数百时&#xff0c;逐个修改微服务配置就会让人抓狂&#xff0c;而且很容易出错。我们需要一种统一配置管理方案&#xff0c;可以集中…

计算时间复杂度详解

1&#xff0c;前置知识 我们在计算时间复杂度之前的前置知识是等差数列的通项公式和求和公式以及等比数 列的通项公式和求和公式 等差数列&#xff1a; 通项公式&#xff1a;ana1(n-1)d&#xff08;d是公差&#xff09; 求和公式&#xff1a;Snn(a1an)/2 等比数列&#xf…

【Python入门知识】NumPy数组拆分,超详细讲解

前言 嗨喽~大家好呀&#xff0c;这里是魔王呐 ❤ ~! 今天我们来学习python中NumPy数组的拆分 拆分 NumPy 数组 拆分是连接的反向操作。 连接&#xff08;Joining&#xff09;是将多个数组合并为一个&#xff0c;拆分&#xff08;Spliting&#xff09;将一个数组拆分为多个。…

Mysql 学习(七)独立表结构存储 二

段的结构 上一节说过表空间分为各个段&#xff0c;每个段里面又是以区为单位&#xff0c;每个区则有64个页。区根据剩余存储空间分为&#xff1a;Free&#xff0c;FREE_FRAG&#xff0c;FULL_FRAG 三种类型&#xff0c;为了方便管理区&#xff0c;给每个区创建XDES Entry结构&…

【校招VIP】用户反驳:你说大厂校招不会问框架实战,现在就有问的了,打脸了吧?一看是专业技能给自己挖的坑

最近有个用户过来质疑&#xff0c;不是说大厂不考框架的使用吗&#xff1f; 但网上的这两份面经里&#xff0c;却问到关于SpringBoot的问题。 接着发来了相对应的简历&#xff0c;一看&#xff0c;直接真相大白&#xff1a; 他在专业技能这栏写了&#xff1a;我熟练掌握Sprin…

flink内存参数配置学习

直接上官网 配置 JobManager 内存 | Apache Flink配置 JobManager 内存 # JobManager 是 Flink 集群的控制单元。 它由三种不同的组件组成&#xff1a;ResourceManager、Dispatcher 和每个正在运行作业的 JobMaster。 本篇文档将介绍 JobManager 内存在整体上以及细粒度…

自动驾驶中地图匹配定位技术总结

引言 汽车定位是让自动驾驶汽车知道自身确切位置的技术&#xff0c;在自动驾驶系统中担负着相当重要的职责。汽车定位涉及多种传感器类型和相关技术&#xff0c;主要可分为卫星定位、惯性导航定位、地图匹配定位以及多传感器融合定位几大类。其中地图匹配定位技术利用道路物理…

CSS绝对定位、相对定位

目录 静态定位 - static 相对定位 - relative 绝对定位 - absolute 固定定位 - fixed z-index属性&#xff1a; 在CSS中定位有以下4种&#xff1a; 静态定位 - static相对定位 - relative绝对定位 - absolute 固定定位 - fixed 静态定位 - static 静态定位是css中的默认定…

网络机顶盒哪个牌子好?资深数码粉分享网络电视机顶盒排名

智能电视配置跟不上经常死机卡顿&#xff0c;但显示正常的情况下不想花钱换电视机怎么办&#xff1f;一台网络机顶盒就可以解决你的烦恼&#xff0c;安装上网络机顶盒以后就可以让旧电视新生&#xff0c;那么你知道网络机顶盒哪个牌子好吗&#xff1f;如果不懂这行&#xff0c;…

【自然语言处理 | Transformer】Transformer:Attention is All You Need论文讲解

Transformer由论文《Attention is All You Need》提出&#xff1a; 论文地址为&#xff1a; https://arxiv.org/pdf/1706.03762.pdf文章目录 一、Transformer 整体结构二、Transformer 的输入2.1 单词 Embedding2.2 位置 Embedding 三、Self-Attention&#xff08;自注意力机制…

.net7 通过 JsonTranscoding 实现 gRPC 与 Web API 一鱼两吃

目标 在一个网站内&#xff0c;用一套proto即提供gPRC 调用&#xff0c;又提供 Web API 调用。 实现方法 根据微软官方James Newton King&#xff08;Newtonsoft.json 作者&#xff09;的文章&#xff0c;.net7 里面提供了 JsonTranscoding 特性&#xff0c;只需要三步&#x…

听我一句劝,别去外包,干了6年,废了....

先说一下自己的情况&#xff0c;大专生&#xff0c;18年通过校招进入湖南某软件公司&#xff0c;干了接近6年的功能测试&#xff0c;今年年初&#xff0c;感觉自己不能够在这样下去了&#xff0c;长时间呆在一个舒适的环境会让一个人堕落!而我已经在一个企业干了6年的功能测试&…

NANK OE骨传导开放式蓝牙耳机发布,极致体验拉满!

近日&#xff0c;中国专业音频品牌NANK南卡发布了全新一代——骨传导开放式蓝牙耳机NANK OE&#xff0c;耳机采用了传统真无线和骨传导的结合方式&#xff0c;带来更加舒适的佩戴体验和音质升级&#xff0c;同时还支持单双耳自由切换&#xff0c;全新的设计收获了市场的喜爱和认…

SignOff Criteria——POCV(Parametric OCV) introduction

文章目录 1. O v e r v i e w Overview Overview2. P O C V A n a l y s i s POCV\ Analysis POCV Analysis3. P O C V F l o w POCV\ Flow POCV Flow4. P O C V R e p o r t POCV\ Report POCV Report 1. O v e r v i e w Overview Overview P r o c e s s v a r i a t i…

数据发送流程

在发送模式下&#xff0c;UART 的串行数据发送电路主要包括一个发送移位寄存器(TSR)&#xff0c;TSR 功能是将数据 逐个移位送出。待发数据必须先写到发送缓冲区中。 TXIFx 是发送中断标志位&#xff0c;可配置为发送缓冲区空或TSR 空。 数据的发送支持7bit 、8bit 或9bit 数据…

JavaScript原型链污染学习记录

1.JS原型和继承机制 0> 原型及其搜索机制 NodeJS原型机制&#xff0c;比较官方的定义&#xff1a; 我们创建的每个函数都有一个 prototype&#xff08;原型&#xff09;属性&#xff0c;这个属性是一个指针&#xff0c;指向一个对象&#xff0c; 而这个对象的用途是包含可…

为什么用Selenium做自动化测试,你真的知道吗?

目录 手工测试的问题 为什么用自动化 选择合适的测试方式 什么时候引入自动化测试 以Jmeter为代表的测试工具 编程能力既重要又不重要 为什么是Selenium 没有最好的技术&#xff0c;只有合适的技术 web自动化测试效率不高 手工测试的问题 手工操作点点点借助的是人脑的…