定时任务
定时任务底层涉及到的数据结构与算法有很多种,如
nginx:红黑树,Go:小顶堆,Linux内核:时间轮
时间轮可以分为简单时间轮和层级时间轮,如下粗糙的实现了基于简单时间轮的定时任务功能。
package main
import (
"fmt"
"sync/atomic"
"time"
)
const SECONDS = 60
type task []struct {
stop bool
doTime uint32
do func()
}
type Timer struct {
seconds [SECONDS]task
currentTime uint32
}
func NewTimer() *Timer {
t := &Timer{
seconds: [60]task{},
currentTime: 0,
}
go func() {
for {
for i := 0; i < 5; i++ {
time.Sleep(time.Millisecond * 200)
}
atomic.StoreUint32(&t.currentTime, atomic.AddUint32(&t.currentTime, +1))
}
}()
go func() {
for {
index := atomic.LoadUint32(&t.currentTime) % SECONDS
tasks := t.seconds[index]
for idx := range tasks {
if tasks[idx].stop == false && tasks[idx].doTime <= atomic.LoadUint32(&t.currentTime) {
tasks[idx].stop = true
go tasks[idx].do()
}
}
for i := 0; i < 3; i++ {
time.Sleep(time.Millisecond * 200)
}
}
}()
return t
}
func (t *Timer) AfterFunc(second uint32, fn func()) {
index := atomic.LoadUint32(&t.currentTime) + second
t.seconds[index%SECONDS] = append(t.seconds[index%SECONDS], struct {
stop bool
doTime uint32
do func()
}{stop: false, doTime: index, do: fn})
}
func main() {
t := NewTimer()
t.AfterFunc(5, func() {
fmt.Println("hello world")
})
t.AfterFunc(60, func() {
fmt.Println("hello world1")
})
t.AfterFunc(10, func() {
fmt.Println("hello 10s")
})
time.Sleep(time.Second * 100)
}