github.com/zhongdalu/gf@v1.0.0/g/os/gtimer/gtimer_entry.go (about) 1 // Copyright 2019 gf Author(https://github.com/zhongdalu/gf). All Rights Reserved. 2 // 3 // This Source Code Form is subject to the terms of the MIT License. 4 // If a copy of the MIT was not distributed with this file, 5 // You can obtain one at https://github.com/zhongdalu/gf. 6 7 package gtimer 8 9 import ( 10 "github.com/zhongdalu/gf/g/container/gtype" 11 "time" 12 ) 13 14 // 循环任务项 15 type Entry struct { 16 wheel *wheel // 所属时间轮 17 job JobFunc // 注册循环任务方法 18 singleton *gtype.Bool // 任务是否单例运行 19 status *gtype.Int // 任务状态(0: ready; 1: running; 2: stopped; -1: closed), 层级entry共享状态 20 times *gtype.Int // 还需运行次数 21 create int64 // 注册时的时间轮ticks 22 interval int64 // 设置的运行间隔(时间轮刻度数量) 23 createMs int64 // 创建时间(毫秒) 24 intervalMs int64 // 间隔时间(毫秒) 25 rawIntervalMs int64 // 原始间隔 26 } 27 28 // 任务执行方法 29 type JobFunc = func() 30 31 // 创建定时任务。 32 // 如果times参数<=0,表示不限制运行次数。 33 func (w *wheel) addEntry(interval time.Duration, job JobFunc, singleton bool, times int, status int) *Entry { 34 if times <= 0 { 35 times = gDEFAULT_TIMES 36 } 37 ms := interval.Nanoseconds() / 1e6 38 num := ms / w.intervalMs 39 if num == 0 { 40 // 如果安装的任务间隔小于时间轮刻度, 41 // 那么将会在下一刻度被执行 42 num = 1 43 } 44 nowMs := time.Now().UnixNano() / 1e6 45 ticks := w.ticks.Val() 46 entry := &Entry{ 47 wheel: w, 48 job: job, 49 times: gtype.NewInt(times), 50 status: gtype.NewInt(status), 51 create: ticks, 52 interval: num, 53 singleton: gtype.NewBool(singleton), 54 createMs: nowMs, 55 intervalMs: ms, 56 rawIntervalMs: ms, 57 } 58 // 安装任务 59 w.slots[(ticks+num)%w.number].PushBack(entry) 60 return entry 61 } 62 63 // 创建定时任务,给定父级Entry, 间隔参数参数为毫秒数. 64 func (w *wheel) addEntryByParent(interval int64, parent *Entry) *Entry { 65 num := interval / w.intervalMs 66 if num == 0 { 67 num = 1 68 } 69 nowMs := time.Now().UnixNano() / 1e6 70 ticks := w.ticks.Val() 71 entry := &Entry{ 72 wheel: w, 73 job: parent.job, 74 times: parent.times, 75 status: parent.status, 76 create: ticks, 77 interval: num, 78 singleton: parent.singleton, 79 createMs: nowMs, 80 intervalMs: interval, 81 rawIntervalMs: parent.rawIntervalMs, 82 } 83 w.slots[(ticks+num)%w.number].PushBack(entry) 84 return entry 85 } 86 87 // 获取任务状态 88 func (entry *Entry) Status() int { 89 return entry.status.Val() 90 } 91 92 // 设置任务状态 93 func (entry *Entry) SetStatus(status int) int { 94 return entry.status.Set(status) 95 } 96 97 // 启动当前任务 98 func (entry *Entry) Start() { 99 entry.status.Set(STATUS_READY) 100 } 101 102 // 停止当前任务 103 func (entry *Entry) Stop() { 104 entry.status.Set(STATUS_STOPPED) 105 } 106 107 // 关闭当前任务 108 func (entry *Entry) Close() { 109 entry.status.Set(STATUS_CLOSED) 110 } 111 112 // 是否单例运行 113 func (entry *Entry) IsSingleton() bool { 114 return entry.singleton.Val() 115 } 116 117 // 设置单例运行 118 func (entry *Entry) SetSingleton(enabled bool) { 119 entry.singleton.Set(enabled) 120 } 121 122 // 设置任务的运行次数 123 func (entry *Entry) SetTimes(times int) { 124 entry.times.Set(times) 125 } 126 127 // 执行任务 128 func (entry *Entry) Run() { 129 entry.job() 130 } 131 132 // 检测当前任务是否可运行。 133 func (entry *Entry) check(nowTicks int64, nowMs int64) (runnable, addable bool) { 134 switch entry.status.Val() { 135 case STATUS_STOPPED: 136 return false, true 137 case STATUS_CLOSED: 138 return false, false 139 } 140 // 时间轮刻度判断,是否满足运行刻度条件,刻度判断的误差会比较大 141 if diff := nowTicks - entry.create; diff > 0 && diff%entry.interval == 0 { 142 // 分层转换处理 143 if entry.wheel.level > 0 { 144 diffMs := nowMs - entry.createMs 145 switch { 146 // 表示新增(当添加任务后在下一时间轮刻度马上触发) 147 case diffMs < entry.wheel.timer.intervalMs: 148 entry.wheel.slots[(nowTicks+entry.interval)%entry.wheel.number].PushBack(entry) 149 return false, false 150 151 // 正常任务 152 case diffMs >= entry.wheel.timer.intervalMs: 153 // 任务是否有必要进行分层转换 154 if leftMs := entry.intervalMs - diffMs; leftMs > entry.wheel.timer.intervalMs { 155 156 // 往底层添加,通过毫秒计算并重新添加任务到对应的时间轮上,减小运行误差 157 entry.wheel.timer.doAddEntryByParent(leftMs, entry) 158 return false, false 159 } 160 } 161 } 162 // 是否单例 163 if entry.IsSingleton() { 164 // 注意原子操作结果判断 165 if entry.status.Set(STATUS_RUNNING) == STATUS_RUNNING { 166 return false, true 167 } 168 } 169 // 次数限制 170 times := entry.times.Add(-1) 171 if times <= 0 { 172 // 注意原子操作结果判断 173 if entry.status.Set(STATUS_CLOSED) == STATUS_CLOSED || times < 0 { 174 return false, false 175 } 176 } 177 // 是否不限制运行次数 178 if times < 2000000000 && times > 1000000000 { 179 entry.times.Set(gDEFAULT_TIMES) 180 } 181 return true, true 182 } 183 return false, true 184 }