[go]timewheel选择

当系统定时任务很多的时候,用标准库的time会增加内存和cpu的使用,所以前辈提出了timewheel的东西,找了一下github上timewheel有挺多的。

看一下前几个

github.com/ouqiang/timewheel

代码超少200行,但是我不太喜欢他的的接口设计... 我是希望接口是和标准库一样的 func AfterFunc(d Duration, f func()) 他func AfterFunc(d Duration, args any)  ;而且不支持定时任务

github.com/rfyiamcool/go-timewheel

支持定时任务;但是用的时候发现定时任务小于timewheel的tk的时候会失效,所以感觉不是很舒服

github.com/antlabs/timer

提供两种实现;默认timer,10ms检查一下任务感觉太频繁;min_heap实现,基本看到没有空跑cpu,感觉他的实现还是不错的(添加任务的时候唤醒运行线程,任务做完了让线程阻塞到下一个任务的触发时间);支持定时任务,支持自定义定时规则。我喜欢这个

 

测试了一下

package main

import (
   "fmt"
   "runtime"
   "sync"
   "time"

   "github.com/antlabs/timer"
   "github.com/rfyiamcool/go-timewheel"
)

func printMem() {
   var m runtime.MemStats
   runtime.ReadMemStats(&m)
   fmt.Printf("%d KB\n", m.Alloc/1024)
}

func main() {
   count := 100000
   d := time.Second * 3

   fmt.Println("\ntimer")
   printMem() // 输出2917 KB
   newTimer := timer.NewTimer(timer.WithMinHeap())
   var wg3 sync.WaitGroup
   for i := 0; i < count; i++ {
      wg3.Add(1)
      newTimer.AfterFunc(d, func() {
         wg3.Done()
      })
   }
   go newTimer.Run()
   printMem() //输出13859 KB
   wg3.Wait()
   newTimer.Stop()
   runtime.GC()
   printMem() // 输出3022 KB

   fmt.Println("\ntimewheel")
   printMem() // 3024 KB
   var wg2 sync.WaitGroup
   for i := 0; i < count; i++ {
      wg2.Add(1)
      timewheel.AfterFunc(d, func() {
         wg2.Done()
      })
   }
   printMem() // 30442 KB
   wg2.Wait()
   runtime.GC()
   printMem() // 5957 KB

   fmt.Println("\nstd time")
   printMem() // 5959 KB
   var wg sync.WaitGroup
   for i := 0; i < count; i++ {
      wg.Add(1)
      time.AfterFunc(d, func() {
         wg.Done()
      })
   }
   printMem() // 18204 KB
   wg.Wait()
   runtime.GC()
   printMem() // 30736 KB
}

测试结果内存方面timer是最好的,然后肉眼观察了一下cpu,标准库cpu会比其它两个高些。

 

挖坑

1. timewheel原理和实现 

2. 为什么timer表现更好

 

posted @ 2023-03-01 15:55  xiaotushaoxia  阅读(155)  评论(0)    收藏  举报