通道计时器,处理事件的新思路

简介: 通道计时器,处理事件的新思路

概述

在 Go 语言中,通道(Channel)和计时器(Timer)是两个强大的并发工具,它们的结合使用可以优雅地处理各种事件。

本文将探讨如何使用通道响应计时器的事件,并通过详实的示例代码展示在不同场景下的应用。


 

1. 通道与计时器基础

1.1 通道的基本概念

通道是 Go 语言中并发编程的核心机制之一,用于在不同的 goroutine 之间传递数据。

make 函数创建


ch := make(chan int)

1.2 计时器的基本概念

计时器是 Go 语言中用于定时执行任务的工具,通过 time 包提供。

创建一个计时器


timer := time.NewTimer(time.Second)


 

2. 使用通道接收计时器事件

2.

package main
import (  "fmt"  "time")
func main() {  ch := make(chan string)
  go func() {    time.Sleep(2 * time.Second)    ch <- "事件发生"  }()
  select {  case msg := <-ch:    fmt.Println(msg)  case <-time.After(3 * time.Second):    fmt.Println("超时,未接收到事件")  }}

在上面示例中,创建了一个通道 ch,并在一个新的 goroutine 中等待 2 秒后往通道发送消息。

select 语句监听通道的消息和计时器的事件,哪个先到达就执行哪个。

2.2 计时器复用


package main
import (  "fmt"  "time")
func main() {  ch := make(chan string)  timer := time.NewTimer(2 * time.Second)
  go func() {    time.Sleep(1 * time.Second)    ch <- "事件发生"  }()
  select {  case msg := <-ch:    fmt.Println(msg)  case <-timer.C:    fmt.Println("超时,未接收到事件")  }}

在上述示例中,创建了一个计时器 timer,它设置为 2 秒。

同样,用 select 监听通道和计时器的事件,但这次用 timer.C 直接监听计时器的事件。


 

3. 使用通道控制计时器

3.1 通道关闭触发计时器


package main
import (  "fmt"  "time")
func main() {  ch := make(chan string)  timer := time.NewTimer(3 * time.Second)
  go func() {    time.Sleep(2 * time.Second)    close(ch)  }()
  select {    case msg, ok := <-ch:    if !ok {      fmt.Println("通道已关闭")      break    }    fmt.Println(msg)    case <-timer.C:    fmt.Println("超时,未接收到事件")  }}

在上面示例中,在 goroutine 中等待 2 秒后关闭通道。

用检查 ok 的值,可以知道通道是否已关闭,从而避免读取已关闭通道引发的异常。

3.

package main
import (  "fmt"  "time")
func main() {  ch := make(chan string, 1)  timer := time.NewTimer(3 * time.Second)
  go func() {    time.Sleep(2 * time.Second)    ch <- "事件发生"  }()
  select {  case msg := <-ch:    fmt.Println(msg)  case <-timer.C:    fmt.Println("超时,未接收到事件")  }}

在这个示例中,将通道 ch 设置为带缓冲的通道,容量为 1。

这样,即使计时器事件先到,通道也能接收到消息,因为有缓冲空间。


 

4. 实战场景

4.1

package main
import (  "fmt"  "time")
func main() {  ticker := time.NewTicker(1 * time.Second)  defer ticker.Stop()
  for {    select {    case <-ticker.C:      fmt.Println("定时任务执行")    }  }}

在上述示例中,使用 time.NewTicker 创建了一个定时器,并通过 select 监听定时器的事件。

在每次定时器触发时,执行相应的周期性任务。

4

package main
import (  "fmt"  "time")
func main() {  ch := make(chan string)
  select {  case msg := <-ch:    fmt.Println(msg)    case <-time.After(3 * time.Second):    fmt.Println("超时,未接收到事件")  }}

在上面示例中,用 time.After 函数创建一个计时器,当超时时,会向通道发送当前时间。

select 监听通道和计时器的事件,实现超时处理。


 

5. 总结

通过本文的讲解和示例代码,了解了如何使用通道响应计时器的事件。

通道和计时器的结合使用能够优雅地处理各种并发场景,包括超时处理、周期性任务等。

当然,使用通道来响应计时器也有一些注意事项:

通道操作需要确保同步正确,避免数据竞争

需要确保不会漏掉计时器的事件

重置计时器时要小心计时和通道处理的时序关系

在使用 Go 语言的并发编程特性时,记住思考通道、同步和事件顺序,这会帮助你编写出高质量和正确的 Go 程序。

目录
相关文章
|
18天前
|
iOS开发 MacOS
简单而高效的计时器
【10月更文挑战第14天】
|
2月前
|
Linux C语言
epoll的水平和边缘触发机制技术分享
在Linux系统中,epoll是一种高效的I/O多路复用机制,用于监视多个文件描述符上的I/O事件。epoll提供了两种主要的工作模式:水平触发(Level Triggered, LT)和边缘触发(Edge Triggered, ET),它们各自在事件通知和处理机制上有所不同。下面将详细探讨这两种触发模式的技术细节和在实际工作学习中的应用。
71 1
|
6月前
基于若依的ruoyi-nbcio流程管理系统支持支持定时边界事件和定时捕获事件
基于若依的ruoyi-nbcio流程管理系统支持支持定时边界事件和定时捕获事件
85 2
|
6月前
|
监控 安全 持续交付
【专栏】Webhook是服务器主动发送事件通知的机制,打破传统客户端轮询模式,实现数据实时高效传递。
【4月更文挑战第29天】Webhook是服务器主动发送事件通知的机制,打破传统客户端轮询模式,实现数据实时高效传递。常用于持续集成部署、第三方服务集成、实时数据同步和监控告警。具有实时性、高效性和灵活性优势,但也面临安全风险和调试挑战。理解并善用Webhook能提升系统性能,广泛应用于现代软件开发和集成。
418 0
|
6月前
|
传感器 人工智能 算法
掌握C++中的状态-事件回调矩阵:打造强大的有限状态机
掌握C++中的状态-事件回调矩阵:打造强大的有限状态机
128 0
|
前端开发
Electron 渲染进程与渲染进程之间的实时通信 (实时触发及接收消息)
Electron 渲染进程与渲染进程之间的实时通信 (实时触发及接收消息)
|
监控 Java API
Java代理技术解密:揭秘方法计时器的神奇实现
本文简单讲讲什么是agent技术,并结合一个方法计时器的实际例子。
|
JavaScript 前端开发
【高频触发事件优化】封装节流和防抖
【高频触发事件优化】封装节流和防抖
167 0
|
存储 缓存 监控
I/O多路复用中的水平触发和边缘触发
I/O多路复用中的水平触发和边缘触发
212 0
|
存储 缓存 小程序
如何实现游戏中的在线计时器和离线计时器
本文包含了游戏中两种计时器的实现原理和实现方法,皆在帮助你彻底的搞懂游戏开发中的计时器。 如果你没有任何的游戏开发经验,欢迎观看我的“人人都能做游戏”系列视频教程,它会手把手的教你做出自己的第一个小游戏。 在游戏中经常会有需要倒计时的需求,例如倒计时 10 分钟可以获得 1 点体力,倒计时 1 小时后可以开启一个宝箱,或者是根据游戏的计时获得奖励等等。
304 0