Go时间轮

方式1

package main

import (
	"fmt"
	"github.com/antlabs/timer"
	"time"
)

type CurstomTest struct {
	count int
}

// 只要实现Next接口就行
func (c *CurstomTest) Next(now time.Time) time.Time {
	rv := now.Add(time.Second) // 设置下一次触发的时间
	c.count++
	return rv
}

func main() {
	tm := timer.NewTimer(timer.WithMinHeap())
	//自定义,这个必须使用最小堆,timer.WithMinHeap()
	cu := &CurstomTest{
		count: 1,
	}
	//延迟1秒
	//tm.AfterFunc(1*time.Second, func() {
	//	fmt.Printf("after\n")
	//})
	//周期
	//tm.ScheduleFunc(1*time.Second, func() {
	//	fmt.Printf("schedule\n")
	//	fmt.Println(cu.count)
	//})
	tm.CustomFunc(cu, func() {
		fmt.Println(cu.count)
	})
	tm.Run()
}

方式二,感觉不如方式1的库方便

package main

import (
	"fmt"
	"github.com/rfyiamcool/go-timewheel"
	"sync"
	"sync/atomic"
	"time"
)

var (
	counter int64 = 0
	loopNum       = 50
	tw            = newTimeWheel()
	wg1           = sync.WaitGroup{}
	log           = new(logger)
)

func incrCounter() {
	atomic.AddInt64(&counter, 1)
}

func main() {
	go printCounter()

	batchRun5s()
	log.info("add finish")
	wg1.Wait()
}

func batchRun5s() {
	worker := 10000
	delay := 5
	beforeDiff := 1
	afterDiff := 2
	processTimer(worker, delay, beforeDiff, afterDiff)

	loop := 5
	taskNum := 50
	go processCallbackLoop(loop, taskNum, delay, beforeDiff, afterDiff)
}

func newTimeWheel() *timewheel.TimeWheel {
	tw, err := timewheel.NewTimeWheel(1*time.Second, 120)
	if err != nil {
		panic(err)
	}
	tw.Start()
	return tw
}

func processTimer(worker, delay, beforeDiff, afterDiff int) {
	for index := 0; index < worker; index++ {
		wg1.Add(1)
		var (
			htimer = tw.NewTimer(time.Duration(delay) * time.Second)
			incr   = 0
		)
		go func(idx int) {
			defer wg1.Done()
			for incr < loopNum {
				now := time.Now()
				target := now.Add(time.Duration(delay) * time.Second)
				select {
				case <-htimer.C:
					htimer.Reset(time.Duration(delay) * time.Second)
					end := time.Now()
					if end.Before(target.Add(time.Duration(-beforeDiff) * time.Second)) {
						log.error("timer befer: %s, delay: %d", time.Since(now).String(), delay)
					}
					if end.After(target.Add(time.Duration(afterDiff) * time.Second)) {
						log.error("timer after: %s, delay: %d", time.Since(now).String(), delay)
					}

					incrCounter()
					// fmt.Println("id: ", idx, "cost: ", end.Sub(now))
				}
				incr++
			}
		}(index)
	}
}

func processCallbackLoop(loop, taskCount, delay, beforeDiff, afterDiff int) {
	wg1.Add(1)
	for index := 0; index < loop; index++ {
		processCallback(taskCount, delay, beforeDiff, afterDiff)
		time.Sleep(time.Duration(delay) * time.Second)
	}
	wg1.Done()
}

func processCallback(taskCount, delay, beforeDiff, afterDiff int) {
	for index := 0; index < taskCount; index++ {
		now := time.Now()
		cb := func() {
			target := now.Add(time.Duration(delay) * time.Second)
			end := time.Now()
			if end.Before(target.Add(time.Duration(-beforeDiff) * time.Second)) {
				log.error("cb befer: %s, delay: %d", time.Since(now).String(), delay)
			}
			if end.After(target.Add(time.Duration(afterDiff) * time.Second)) {
				log.error("cb after: %s, delay: %d", time.Since(now).String(), delay)
			}
			incrCounter()
			// log.info("cost: %s, delay: %d", end.Sub(now), delay)
		}
		tw.Add(time.Duration(delay)*time.Second, cb)
	}
}

func printCounter() {
	now := time.Now()
	for {
		n := atomic.LoadInt64(&counter)
		log.info("start_time: %s, since_time: %s, counter %d", now.String(), time.Since(now).String(), n)
		time.Sleep(10 * time.Second)
	}
}

type logger struct{}

func (l *logger) info(format string, args ...interface{}) {
	v := fmt.Sprintf(format, args...)
	fmt.Println(v)
}

func (l *logger) error(format string, args ...interface{}) {
	v := fmt.Sprintf(format, args...)
	color := fmt.Sprintf("%c[%d;%d;%dm %s %c[0m", 0x1B, 5, 40, 31, v, 0x1B)
	fmt.Println(color)
}
posted @ 2024-10-08 16:15  朝阳1  阅读(23)  评论(0)    收藏  举报