Golang当中的定时器

这篇具有很好参考价值的文章主要介绍了Golang当中的定时器。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

前言

在平时写代码的时候,我们经常会遇到在将来某个时间点或者间隔一段时间重复执行函数。这个时候我们就可以考虑使用定时器。本片文章主要介绍一下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)
		}
	}
	
}

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

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

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

总结:文章来源地址https://www.toymoban.com/news/detail-465091.html

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

到了这里,关于Golang当中的定时器的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【Linux】Linux定时器使用及代码案例

    在 Linux 中,可以使用定时器来实现一些定时任务,例如定时发送信号、定时执行某个函数等。定时器的初始化通常包括以下几个步骤: 定义定时器结构体:首先需要定义一个定时器结构体,用于存储定时器的相关信息。在 Linux 中,可以使用 timer_t 类型来表示定时器结构体。

    2024年02月04日
    浏览(37)
  • [AIGC] 深入理解Flink中的窗口、水位线和定时器

    Apache Flink是一种流处理和批处理的混合引擎,它提供了一套丰富的APIs,以满足不同的数据处理需求。在本文中,我们主要讨论Flink中的三个核心机制:窗口(Windows)、水位线(Watermarks)和定时器(Timers)。 在流处理应用中,一种常见的需求是计算某个时间范围内的数据,这

    2024年03月27日
    浏览(59)
  • ARM Cortex-M处理器中的SysTick定时器简介

    ARM Cortex-M处理器中的SysTick是一个内部的系统定时器,它提供了一种简单而有效的方式来生成定时的中断请求。SysTick定时器是一个24位的下计数定时器,它可以配置为周期性地产生中断,这些中断可以用于操作系统的任务调度、性能测量、时间延迟等。 SysTick定时器的主要特点

    2024年04月28日
    浏览(49)
  • 自定义循环队列、软件定时器、事件集,实用嵌入式代码库

    本篇博文分享一个很实用的嵌入式代码库。 它可灵活应用到有无RTOS的程序中,采用C语言面向对象的思路实现各个功能,尽可能最大化的复用代码,目前为止工具包包含: 循环队列、软件定时器、事件集 。 网址:https://download.csdn.net/download/m0_38106923/87765476?spm=1001.2014.3001.550

    2024年02月03日
    浏览(56)
  • 搭建stm32电机控制代码框架(二)——Stm32CubeMx配置定时器

    搭建了基础的环境,配置了一个简单的工程后,CubeMx的基本操作就会了。然后基于这个操作往下推进,开始对关键模块定时器的攻略,这个部分需要先熟悉一下Stm32的定时器基本原理。 《STM32参考手册》中仅对定时器的介绍就已经占了100多页,这里就不一一展开,挑一些关键

    2024年02月06日
    浏览(81)
  • 电子定时器洗衣机控制Verilog代码Quartus 睿智FPGA开发板

    名称:电子定时器洗衣机控制Verilog代码Quartus   睿智FPGA开发板(文末获取) 软件:Quartus 语言:Verilog 代码功能: 1.设计一个电子定时器,控制洗衣机作如下运转:定时启动,正转20秒,暂停10秒,反 转20秒,暂停10秒,定时未到回到“正转20秒暂停10秒..... 2.若定时到,则停机发

    2024年01月20日
    浏览(53)
  • 【STM32学习】——定时器输出比较功能&PWM脉宽调制&通用/高级定时器输出比较通道&舵机/直流电机简介&PWM驱动呼吸灯/舵机/直流电机代码实操

    声明:学习笔记根据b站江科大自化协stm32入门教程编辑,仅供学习交流使用!

    2024年02月03日
    浏览(58)
  • Linux中的alarm和setitimer定时器函数以及信号捕捉函数signal和sigaction

    通过 man 2 alarm 查看alarm函数的详细信息。 功能: 设置定时器(闹钟)。从调用这个函数开始进行倒计时,倒计时结束之后(变为0),函数会给当前的进程发送 SIGALARM 信号。 参数: seconds: 倒计时的时长,单位:秒。如果参数为0,定时器无效(不进行倒计时,不发信号)。取

    2024年02月03日
    浏览(56)
  • 【蓝桥杯嵌入式】定时器实现按键单击,双击,消抖以及长按的代码实现

    🎊【蓝桥杯嵌入式】专题正在持续更新中,原理图解析✨,各模块分析✨以及历年真题讲解✨都在这儿哦,欢迎大家前往订阅本专题,获取更多详细信息哦🎏🎏🎏 🪔本系列专栏 -  蓝桥杯嵌入式_勾栏听曲_0的博客 🍻欢迎大家  🏹  点赞👍  评论📨  收藏⭐️ 📌个人主

    2024年01月17日
    浏览(49)
  • Zinx框架-游戏服务器开发002:框架学习-按照三层结构模式重构测试代码+Tcp数据适配+时间轮定时器

    三层结构重构原有功能 自定义消息类,继承UserData,添加一个成员变量szUserData 定义多个Role类继承Irole,重写ProcMsg函数,进行不同处理 定义protocol类,继承Iprotocol,重写四个函数,两个函数时原始 数据和用户数据之间的转换;另两个用来找消息处理对象和消息发 送对象。 定

    2024年02月05日
    浏览(57)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包