mirror of
https://gitee.com/johng/gf.git
synced 2024-12-01 03:38:35 +08:00
154 lines
4.6 KiB
Go
154 lines
4.6 KiB
Go
// Copyright 2019 gf Author(https://gitee.com/johng/gf). All Rights Reserved.
|
|
//
|
|
// This Source Code Form is subject to the terms of the MIT License.
|
|
// If a copy of the MIT was not distributed with this file,
|
|
// You can obtain one at https://gitee.com/johng/gf.
|
|
|
|
package gtimer
|
|
|
|
import (
|
|
"gitee.com/johng/gf/g/container/gtype"
|
|
"time"
|
|
)
|
|
|
|
// 循环任务项
|
|
type Entry struct {
|
|
job JobFunc // 注册循环任务方法
|
|
wheel *wheel // 所属时间轮
|
|
singleton *gtype.Bool // 任务是否单例运行
|
|
status *gtype.Int // 任务状态(0: ready; 1: running; -1: closed)
|
|
times *gtype.Int // 还需运行次数
|
|
create int64 // 注册时的时间轮ticks
|
|
interval int64 // 设置的运行间隔(时间轮刻度数量)
|
|
createMs int64 // 创建时间(毫秒)
|
|
updateMs int64 // 更新时间(上一次检查/运行时间, 毫秒)
|
|
intervalMs int64 // 间隔时间(毫秒)
|
|
}
|
|
|
|
// 任务执行方法
|
|
type JobFunc = func()
|
|
|
|
// 创建定时任务
|
|
func (w *wheel) addEntry(interval time.Duration, job JobFunc, singleton bool, times int) *Entry {
|
|
ms := interval.Nanoseconds()/1e6
|
|
num := ms/w.intervalMs
|
|
if num == 0 {
|
|
// 如果安装的任务间隔小于时间轮刻度,
|
|
// 那么将会在下一刻度被执行
|
|
num = 1
|
|
}
|
|
nowMs := time.Now().UnixNano()/1e6
|
|
ticks := w.ticks.Val()
|
|
entry := &Entry {
|
|
wheel : w,
|
|
singleton : gtype.NewBool(singleton),
|
|
status : gtype.NewInt(STATUS_READY),
|
|
times : gtype.NewInt(times),
|
|
job : job,
|
|
create : ticks,
|
|
interval : num,
|
|
createMs : nowMs,
|
|
updateMs : nowMs,
|
|
intervalMs : ms,
|
|
}
|
|
// 安装任务
|
|
w.slots[(ticks + num) % w.number].PushBack(entry)
|
|
return entry
|
|
}
|
|
|
|
// 递增添加任务
|
|
func (w *wheel) reAddEntry(entry *Entry, nowTicks int64, nowMs int64) {
|
|
left := entry.interval - (nowTicks - entry.create)
|
|
if left <= 0 {
|
|
left = entry.interval
|
|
entry.create = nowTicks
|
|
entry.createMs = nowMs
|
|
entry.updateMs = nowMs
|
|
}
|
|
w.slots[(nowTicks + left) % w.number].PushBack(entry)
|
|
}
|
|
|
|
// 获取任务状态
|
|
func (entry *Entry) Status() int {
|
|
return entry.status.Val()
|
|
}
|
|
|
|
// 设置任务状态
|
|
func (entry *Entry) SetStatus(status int) int {
|
|
return entry.status.Set(status)
|
|
}
|
|
|
|
// 关闭当前任务
|
|
func (entry *Entry) Close() {
|
|
entry.status.Set(STATUS_CLOSED)
|
|
}
|
|
|
|
// 是否单例运行
|
|
func (entry *Entry) IsSingleton() bool {
|
|
return entry.singleton.Val()
|
|
}
|
|
|
|
// 设置单例运行
|
|
func (entry *Entry) SetSingleton(enabled bool) {
|
|
entry.singleton.Set(enabled)
|
|
}
|
|
|
|
// 设置任务的运行次数
|
|
func (entry *Entry) SetTimes(times int) {
|
|
entry.times.Set(times)
|
|
}
|
|
|
|
// 执行任务
|
|
func (entry *Entry) Run() {
|
|
entry.job()
|
|
}
|
|
|
|
// 检测当前任务是否可运行, 参数为当前时间的纳秒数, 精度更高
|
|
func (entry *Entry) check(nowTicks int64, nowMs int64) bool {
|
|
// 运行检查
|
|
if diff := nowTicks - entry.create; diff > 0 && diff%entry.interval == 0 {
|
|
// 是否单例
|
|
if entry.IsSingleton() {
|
|
if entry.status.Set(STATUS_RUNNING) == STATUS_RUNNING {
|
|
return false
|
|
}
|
|
}
|
|
// 次数限制
|
|
times := entry.times.Add(-1)
|
|
if times <= 0 {
|
|
entry.status.Set(STATUS_CLOSED)
|
|
if times < 0 {
|
|
return false
|
|
}
|
|
}
|
|
// 是否不限制运行次数
|
|
if times < 2000000000 && times > 1000000000 {
|
|
times = gDEFAULT_TIMES
|
|
entry.times.Set(gDEFAULT_TIMES)
|
|
}
|
|
// 分层转换
|
|
if entry.wheel.level > 0 {
|
|
if diffMs := nowMs - entry.updateMs; diffMs < entry.intervalMs {
|
|
if leftMs := entry.intervalMs - diffMs; leftMs > entry.wheel.wheels.intervalMs {
|
|
delay := time.Duration(leftMs)*time.Millisecond
|
|
// 往底层添加
|
|
entry.wheel.wheels.addEntry(delay, entry.job, false, 1)
|
|
// 延迟重新添加
|
|
if times > 0 {
|
|
entry.wheel.wheels.DelayAddTimes(
|
|
delay,
|
|
time.Duration(entry.intervalMs)*time.Millisecond,
|
|
times,
|
|
entry.job,
|
|
)
|
|
}
|
|
entry.status.Set(STATUS_CLOSED)
|
|
return false
|
|
}
|
|
}
|
|
}
|
|
return true
|
|
}
|
|
return false
|
|
}
|