應用場景
電池船資料上報頻次:航行中 1次/30秒,不航行 1次/1小時
電池簇資料上報頻次:工作中 1次/1秒,不工作 不上報
main.go
package main import ( "fmt" "os" "os/signal" "syscall" "ticker/util" "time" ) var ticker1 *util.DynamicTicker var ticker2 *util.DynamicTicker func report_batteryship() { // 航行時1秒/次,不航行時10秒/次 fmt.Println("report_batteryship:", time.Now()) } func report_batterycluster() { // 工作時1秒/次,不工作時不上報 fmt.Println("report_batterycluster:", time.Now()) } func main() { sleeptime := 10 * time.Second // ticker1 = util.NewDynamicTicker(1*time.Second, report_batteryship) // ticker1.SetWorkStatus(true) // go func() { // fmt.Println("航行中") // time.Sleep(sleeptime) // fmt.Println("不航行") // ticker1.ChangeInterval(10 * time.Second) // time.Sleep(sleeptime * 6) // fmt.Println("航行中") // ticker1.ChangeInterval(1 * time.Second) // }() ticker2 = util.NewDynamicTicker(2*time.Second, report_batterycluster) ticker2.SetWorkStatus(true) go func() { fmt.Println("開始工作") time.Sleep(sleeptime) fmt.Println("停止工作") ticker2.SetWorkStatus(false) time.Sleep(sleeptime) fmt.Println("開始工作") ticker2.SetWorkStatus(true) }() // 監聽作業系統訊號,阻塞直到接收到訊號 quit := make(chan os.Signal, 1) signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM) <-quit }
ticker.go
package util import ( "sync" "time" ) // 是一個可以動態改變時間間隔的定時器 type DynamicTicker struct { currentTicker *time.Ticker // 當前正在使用的 ticker nextTicker *time.Ticker // 下一個要切換到的 ticker work bool // 工作狀態標誌 quit chan struct{} // 用於停止 goroutine 的訊號通道 mu sync.Mutex // 互斥鎖,用於保護併發訪問 worker func() // 定時執行的工作函式 wg sync.WaitGroup // 等待組,用於等待 goroutine 結束 } // 建立一個新的 DynamicTicker 例項 func NewDynamicTicker(interval time.Duration, worker func()) *DynamicTicker { dt := &DynamicTicker{ currentTicker: time.NewTicker(interval), // 初始化當前 ticker quit: make(chan struct{}), // 初始化停止訊號通道 worker: worker, // 設定工作函式 } dt.wg.Add(1) // 增加等待組的計數器 go dt.run() // 啟動 goroutine 執行 run 方法 return dt } // 監聽訊號 func (dt *DynamicTicker) run() { defer dt.wg.Done() // 在 goroutine 結束時減少等待組的計數器 for { select { case <-dt.currentTicker.C: // 接收到當前 ticker 的訊號 dt.mu.Lock() if dt.work { // 如果處於工作狀態 dt.worker() // 執行工作函式 } // 如果存在下一個 ticker,則切換到下一個 ticker if dt.nextTicker != nil { dt.currentTicker.Stop() // 停止當前 ticker dt.currentTicker = dt.nextTicker // 切換到下一個 ticker dt.nextTicker = nil // 重置下一個 ticker } dt.mu.Unlock() case <-dt.quit: // 接收到停止訊號 dt.currentTicker.Stop() // 停止當前 ticker if dt.nextTicker != nil { // 如果存在下一個 ticker,也停止它 dt.nextTicker.Stop() } return // 退出 goroutine } } } // 動態改變定時器的間隔 func (dt *DynamicTicker) ChangeInterval(newInterval time.Duration) { dt.mu.Lock() defer dt.mu.Unlock() dt.nextTicker = time.NewTicker(newInterval) // 建立新的 ticker 作為下一個 ticker } // 設定定時器的工作狀態 func (dt *DynamicTicker) SetWorkStatus(work bool) { dt.mu.Lock() defer dt.mu.Unlock() dt.work = work // 更新工作狀態 } // 停止定時器 func (dt *DynamicTicker) Stop() { close(dt.quit) // 關閉停止訊號通道 dt.wg.Wait() // 等待 goroutine 結束 }