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  }