go定时器文档:https://pkg.go.dev/time@go1.24.2#Ticker
func NewTicker(d Duration) *Ticker
NewTicker返回一个新的Ticker,其中包含一个通道,该通道将在每次duration之后发送通道上的当前时间。节拍的周期由duration参数指定。
Go 定时器设计与企业应用场景详解
示例代码解析
func main() {
t1 := time.NewTicker(time.Second * 1) // 创建一个周期定时器
var i = 1
for {
if i == 10 {
break
}
select {
case <-t1.C: // 一秒执行一次的定时任务
task1(i)
i++
}
}
}
func task1(i int) {
fmt.Println("task1执行了---", i)
}
这段代码创建了一个每秒触发一次的定时器,共执行9次(i从1到9)后退出。这是定时器的基本用法,但实际企业应用中会更复杂。
定时器类型详解
Go语言中有两种主要定时器:
-
Ticker(周期定时器) - 周期性触发
ticker := time.NewTicker(time.Second) defer ticker.Stop() // 使用完毕后记得释放资源
-
Timer(一次性定时器) - 只触发一次
timer := time.NewTimer(time.Second) defer timer.Stop()
企业级应用场景案例
场景1:后台数据同步服务
func main() {
syncTicker := time.NewTicker(5 * time.Minute)
defer syncTicker.Stop()
errorTicker := time.NewTicker(30 * time.Second)
defer errorTicker.Stop()
for {
select {
case <-syncTicker.C:
// 每5分钟同步一次数据
if err := syncData(); err != nil {
log.Printf("数据同步失败: %v", err)
// 失败后改为每30秒重试
syncTicker.Reset(30 * time.Second)
} else {
// 成功后恢复5分钟间隔
syncTicker.Reset(5 * time.Minute)
}
case <-errorTicker.C:
// 监控并报告服务状态
checkServiceHealth()
}
}
}
func syncData() error {
// 模拟数据同步逻辑
fmt.Println("执行数据同步...", time.Now().Format("15:04:05"))
if time.Now().Second()%3 == 0 { // 模拟随机失败
return fmt.Errorf("模拟同步错误")
}
return nil
}
func checkServiceHealth() {
fmt.Println("检查服务健康状态...", time.Now().Format("15:04:05"))
}
特点:
- 多定时器组合使用
- 根据执行结果动态调整定时间隔
- 包含错误处理逻辑
场景2:API请求限流控制
func main() {
reqLimiter := time.NewTicker(100 * time.Millisecond) // 每秒最多10次请求
defer reqLimiter.Stop()
for i := 0; i < 20; i++ {
<-reqLimiter.C
go func(count int) {
resp, err := callAPI(count)
if err != nil {
log.Printf("API调用%d失败: %v", count, err)
return
}
log.Printf("API调用%d成功: %s", count, resp)
}(i)
}
time.Sleep(2 * time.Second) // 等待所有请求完成
}
func callAPI(count int) (string, error) {
// 模拟API调用
fmt.Printf("调用API #%d\n", count)
if count%7 == 0 { // 模拟偶尔失败
return "", fmt.Errorf("API错误")
}
return "成功响应", nil
}
特点:
- 使用定时器实现请求速率控制
- 并发安全地处理请求
- 错误处理和日志记录
场景3:任务超时控制
func main() {
resultChan := make(chan string)
// 启动一个可能长时间运行的任务
go longRunningTask(resultChan)
// 设置3秒超时
timeout := time.NewTimer(3 * time.Second)
defer timeout.Stop()
select {
case res := <-resultChan:
fmt.Println("任务完成:", res)
case <-timeout.C:
fmt.Println("任务超时!")
}
}
func longRunningTask(ch chan<- string) {
// 模拟耗时任务,随机2-5秒
duration := 2 + rand.Intn(3)
time.Sleep(time.Duration(duration) * time.Second)
ch <- fmt.Sprintf("耗时%d秒完成", duration)
}
特点:
- 防止任务无限期阻塞
- 使用Timer实现超时控制
- 清晰的超时处理逻辑
定时器使用最佳实践
- 资源释放:总是使用
defer ticker.Stop()
或defer timer.Stop()
- 避免泄漏:确保能从定时器的channel中读取,否则可能导致goroutine泄漏
- 重置定时器:使用
Reset()
方法而不是创建新定时器 - 并发安全:定时器本身是并发安全的,但业务逻辑需要自己保证
- 精度问题:定时器不保证精确时间,受系统调度影响
改进初始示例
func main() {
ticker := time.NewTicker(time.Second)
defer ticker.Stop() // 添加资源释放
for i := 1; i < 10; i++ { // 简化循环逻辑
<-ticker.C
task1(i)
// 动态调整间隔示例
if i%3 == 0 {
ticker.Reset(2 * time.Second) // 每3次后改为2秒间隔
} else {
ticker.Reset(time.Second) // 恢复1秒间隔
}
}
}
func task1(i int) {
fmt.Printf("任务执行 #%d - %s\n", i, time.Now().Format("15:04:05"))
}
https://github.com/0voice