業務中有很多定時任務,在規定時間內,不管是否完成都需要回調,明顯,這種需要實現定時器,比較好的是時間輪和最小堆。這裡介紹最小堆實現,這裡就是個變相的topN 問題。
該文章後續仍在不斷的更新修改中, 請移步到原文地址http://www.dmwan.cc/?p=146
由於是項目中要使用,不能僅考慮最小堆就完事,需要添加幾條特性,第一個是要用一個timer 實現計時功能,第二個是要有提前刪除功能。特別提下第二點,在高並發的情況下,timer 不能讓任務自動到期,業務成功的情況下,要能提前刪除,否則,timer壓力會越來越大;
項目github地址:https://github.com/caucy/timeloop。
調用樣本:
package mainimport ("os""fmt""time""os/signal""strconv""syscall""timeloop/timer")var (timerCtl *timer.TimerHeapHandler)func init() {timerCtl = timer.New(10, 1000)}type timerHandler struct {}func AddTimerTask(dueInterval int, taskId string) {timerCtl.AddFuncWithId(time.Duration(dueInterval)*time.Second, taskId, func() {fmt.Printf("taskid is %v, time Duration is %v", taskId, dueInterval )})}func (t *timerHandler) StartLoop() {timerCtl.StartTimerLoop(timer.MIN_TIMER) // 掃描的間隔時間 eq cpu hz/tick}func main() {sigs := make(chan os.Signal, 1)signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)timerEntry := timerHandler{}timerEntry.StartLoop()num := 5000interval := 1000 * time.Millisecondgo func (){for i := 0; i < num; i++ {taskId := strconv.Itoa(i)timerCtl.AddFuncWithId(10 *interval, taskId, func() {fmt.Printf("taskid is %v, time Duration is %v \n", taskId, interval )})time.Sleep(100 * time.Millisecond)}}()<- sigs}
實現的主要思路就是,維護個最小堆,每次push,pop 的時候調整堆產生最小堆,一個時鐘,每隔一段時間去pop 所有逾時的任務,放入非同步消費隊列中去。 在高頻的逾時任務管理中,這種類庫還是很有用的。