// 定时协程 // 定时或发通知调用协程函数 package coroutine import ( "context" "leafstalk/log" "sync" "time" ) // TimerRoutine 定时协程类 type TimerRoutine struct { name string interval time.Duration chEvent chan struct{} wg sync.WaitGroup cancel context.CancelFunc taskFunc func() // 定时执行的任务函数 } // NewTimerRoutine 创建一个定时协程实例 func NewTimerRoutine(name string, interval time.Duration, taskFunc func()) *TimerRoutine { return &TimerRoutine{ name: name, interval: interval, chEvent: make(chan struct{}, 1), taskFunc: taskFunc, } } // Start 启动定时协程 func (tr *TimerRoutine) Start() { ctx, cancel := context.WithCancel(context.Background()) tr.cancel = cancel tr.wg.Add(1) go func() { defer func() { tr.wg.Done() log.Infof("TimerRoutine.Start exit %s", tr.name) }() tr.run(ctx) }() } // Stop 停止定时协程,等待协程退出 func (tr *TimerRoutine) Stop() { tr.cancel() tr.wg.Wait() } // Notify 发送事件通知,触发任务执行 func (tr *TimerRoutine) Notify() { select { case tr.chEvent <- struct{}{}: default: } } // run 定时协程的核心逻辑 func (tr *TimerRoutine) run(ctx context.Context) { ticker := time.NewTicker(tr.interval) defer func() { ticker.Stop() log.Infof("TimerRoutine.run exit %s", tr.name) }() safeDo := func() { defer func() { if err := recover(); err != nil { // 处理 panic,例如记录日志 log.Infof("TimerRoutine recover panic %s: %v", tr.name, err) } }() tr.taskFunc() } for { select { case <-ctx.Done(): return case <-ticker.C: case <-tr.chEvent: } if tr.taskFunc != nil { safeDo() } } } func example1() { timerRoutine := NewTimerRoutine("MyTimer", time.Second*5, func() { }) timerRoutine.Start() timerRoutine.Stop() }