go里面关于超时的设计

设想一下你在接收源源不断的数据,如果有700ms没有收到,则认为是一个超时,需要做出处理。

逻辑上可以设计一个grouting,里面放一个通道,每收到一条数据进行相应处理。通道中夹杂一个timer定时器的处理,若通道在700ms内有数据,则定时器被重置,重新等待700ms再调用定时器处理函数,否则,700ms时间到,运行定时器处理函数。示例代码如下:

Go 复制代码
​
package main

import (
	"fmt"
	"runtime/debug"
	"strings"
	"time"
)

type demoSaveSuite struct {
	chanDemoSave chan string
}

const dbSaveWaitDuration = 700 * time.Millisecond

func (s *demoSaveSuite) DemoHandler() {
	go func() {
		defer func() {
			if r := recover(); r != nil {
				fmt.Println(string(debug.Stack()))
			}
		}()
		var timer *time.Timer
		for sqlEntity := range s.chanDemoSave {
			fmt.Printf("Received SQL entity: %s\n", sqlEntity)
			// 检查 sqlEntity 是否包含 "SQL_Entity_5"
			if strings.Contains(sqlEntity, "SQL_Entity_5") {
				if timer != nil {
					timer.Stop()
					timer = nil // 将 timer 设为 nil 以确保不再使用它
					continue    // 跳过本次循环的后续部分
				}
			}

			if timer == nil {
				timer = time.AfterFunc(dbSaveWaitDuration, func() {
					fmt.Printf("Executing action after delay for entity: %s\n", sqlEntity)
				})
			} else {
				timer.Reset(dbSaveWaitDuration)
			}
		}
	}()
}

func main() {
	// You can place your main code here if needed
	suite := &demoSaveSuite{
		chanDemoSave: make(chan string, 5), // Buffer to avoid blocking when sending messages
	}

	go suite.DemoHandler()

	// Send the first SQL entity
	suite.chanDemoSave <- "SQL_Entity_1_300Millisecond"
	time.Sleep(300 * time.Millisecond) // sleep a bit, but not enough for dbSaveWaitDuration

	// Send the second SQL entity
	suite.chanDemoSave <- "SQL_Entity_2_800Millisecond"
	time.Sleep(800 * time.Millisecond) // let the timer expire for SQL_Entity_1

	// Send the third SQL entity to test resetting the timer
	suite.chanDemoSave <- "SQL_Entity_3_300Millisecond"
	time.Sleep(300 * time.Millisecond) // sleep a bit, but not enough for dbSaveWaitDuration

	// Send the fourth SQL entity
	suite.chanDemoSave <- "SQL_Entity_4_800Millisecond"
	time.Sleep(800 * time.Millisecond) // let the timer expire for SQL_Entity_3

	// Send the fourth SQL entity
	suite.chanDemoSave <- "SQL_Entity_5_2500Millisecond"
	time.Sleep(2500 * time.Millisecond) // let the timer expire for SQL_Entity_3

	// Close the channel
	close(suite.chanDemoSave)
}

​

代码动行结果:

Go 复制代码
Received SQL entity: SQL_Entity_1_300Millisecond
Received SQL entity: SQL_Entity_2_800Millisecond
Executing action after delay for entity: SQL_Entity_2_800Millisecond
Received SQL entity: SQL_Entity_3_900Millisecond
Received SQL entity: SQL_Entity_4_800Millisecond
Executing action after delay for entity: SQL_Entity_4_800Millisecond
Received SQL entity: SQL_Entity_5_2500Millisecond
Executing action after delay for entity: SQL_Entity_5_2500Millisecond

从运行结果看,只要超过700ms没有数据进入,就会引发定时器的回调,并且从2500ms的超时看只激发了一次,说明这里的定时器只会运行一次。没有超过700ms的,由于定时器被重置了,又开始等700ms才会运行,运行SQL_Entity_3时,定时器被删除,从结果看,虽然间隔是900ms远超700ms,依然定时器没有执行。接收到SQL_Entity_4时,由于timer已经为nil,因此又重新开启定时器

相关推荐
Yurko131 分钟前
【C语言】环境安装(图文)与介绍
c语言·开发语言·学习
仲星(._.)2 分钟前
C语言:字符函数和字符串函数
c语言·开发语言
kyle~4 分钟前
C++---向上取整
开发语言·c++
QX_hao10 分钟前
【Go】--扩容机制
开发语言·golang
weixin_3077791311 分钟前
Clickhouse导出库的表、视图、用户和角色定义的SQL语句
开发语言·数据库·算法·clickhouse·自动化
流星白龙24 分钟前
【Qt】7.信号和槽_connect函数用法(1)
开发语言·数据库·qt
小龙报40 分钟前
《算法通关指南---C++编程篇(1)》
开发语言·c++·程序人生·算法·学习方法·visual studio
Cx330❀1 小时前
《C++ 手搓list容器底层》:从结构原理深度解析到功能实现(附源码版)
开发语言·数据结构·c++·经验分享·算法·list
CC.GG1 小时前
【C++】STL容器--list的使用
开发语言·c++·list
洲覆1 小时前
基于 clangd 搭建 Redis 6.2 源码阅读与调试环境
开发语言·数据库·redis·缓存