【go】周期定时器time.Ticker和一次性定时器Timer,使用案例,自存档

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语言中有两种主要定时器:

  1. Ticker(周期定时器) - 周期性触发

    ticker := time.NewTicker(time.Second)
    defer ticker.Stop() // 使用完毕后记得释放资源
    
  2. 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实现超时控制
  • 清晰的超时处理逻辑

定时器使用最佳实践

  1. 资源释放:总是使用defer ticker.Stop()defer timer.Stop()
  2. 避免泄漏:确保能从定时器的channel中读取,否则可能导致goroutine泄漏
  3. 重置定时器:使用Reset()方法而不是创建新定时器
  4. 并发安全:定时器本身是并发安全的,但业务逻辑需要自己保证
  5. 精度问题:定时器不保证精确时间,受系统调度影响

改进初始示例

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值