github.com/zhongdalu/gf@v1.0.0/g/os/gtimer/gtimer_timer.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/glist"
    11  	"github.com/zhongdalu/gf/g/container/gtype"
    12  	"time"
    13  )
    14  
    15  // 定时器/分层时间轮
    16  type Timer struct {
    17  	status     *gtype.Int // 定时器状态
    18  	wheels     []*wheel   // 分层时间轮对象
    19  	length     int        // 分层层数
    20  	number     int        // 每一层Slot Number
    21  	intervalMs int64      // 最小时间刻度(毫秒)
    22  }
    23  
    24  // 单层时间轮
    25  type wheel struct {
    26  	timer      *Timer        // 所属定时器
    27  	level      int           // 所属分层索引号
    28  	slots      []*glist.List // 所有的循环任务项, 按照Slot Number进行分组
    29  	number     int64         // Slot Number=len(slots)
    30  	ticks      *gtype.Int64  // 当前时间轮已转动的刻度数量
    31  	totalMs    int64         // 整个时间轮的时间长度(毫秒)=number*interval
    32  	createMs   int64         // 创建时间(毫秒)
    33  	intervalMs int64         // 时间间隔(slot时间长度, 毫秒)
    34  }
    35  
    36  // 创建分层时间轮
    37  func New(slot int, interval time.Duration, level ...int) *Timer {
    38  	length := gDEFAULT_WHEEL_LEVEL
    39  	if len(level) > 0 {
    40  		length = level[0]
    41  	}
    42  	t := &Timer{
    43  		status:     gtype.NewInt(STATUS_RUNNING),
    44  		wheels:     make([]*wheel, length),
    45  		length:     length,
    46  		number:     slot,
    47  		intervalMs: interval.Nanoseconds() / 1e6,
    48  	}
    49  	for i := 0; i < length; i++ {
    50  		if i > 0 {
    51  			n := time.Duration(t.wheels[i-1].totalMs) * time.Millisecond
    52  			w := t.newWheel(i, slot, n)
    53  			t.wheels[i] = w
    54  			t.wheels[i-1].addEntry(n, w.proceed, false, gDEFAULT_TIMES, STATUS_READY)
    55  		} else {
    56  			t.wheels[i] = t.newWheel(i, slot, interval)
    57  		}
    58  	}
    59  	t.wheels[0].start()
    60  	return t
    61  }
    62  
    63  // 创建自定义的循环任务管理对象
    64  func (t *Timer) newWheel(level int, slot int, interval time.Duration) *wheel {
    65  	w := &wheel{
    66  		timer:      t,
    67  		level:      level,
    68  		slots:      make([]*glist.List, slot),
    69  		number:     int64(slot),
    70  		ticks:      gtype.NewInt64(),
    71  		totalMs:    int64(slot) * interval.Nanoseconds() / 1e6,
    72  		createMs:   time.Now().UnixNano() / 1e6,
    73  		intervalMs: interval.Nanoseconds() / 1e6,
    74  	}
    75  	for i := int64(0); i < w.number; i++ {
    76  		w.slots[i] = glist.New()
    77  	}
    78  	return w
    79  }
    80  
    81  // 添加循环任务
    82  func (t *Timer) Add(interval time.Duration, job JobFunc) *Entry {
    83  	return t.doAddEntry(interval, job, false, gDEFAULT_TIMES, STATUS_READY)
    84  }
    85  
    86  // 添加定时任务
    87  func (t *Timer) AddEntry(interval time.Duration, job JobFunc, singleton bool, times int, status int) *Entry {
    88  	return t.doAddEntry(interval, job, singleton, times, status)
    89  }
    90  
    91  // 添加单例运行循环任务
    92  func (t *Timer) AddSingleton(interval time.Duration, job JobFunc) *Entry {
    93  	return t.doAddEntry(interval, job, true, gDEFAULT_TIMES, STATUS_READY)
    94  }
    95  
    96  // 添加只运行一次的循环任务
    97  func (t *Timer) AddOnce(interval time.Duration, job JobFunc) *Entry {
    98  	return t.doAddEntry(interval, job, true, 1, STATUS_READY)
    99  }
   100  
   101  // 添加运行指定次数的循环任务。
   102  func (t *Timer) AddTimes(interval time.Duration, times int, job JobFunc) *Entry {
   103  	return t.doAddEntry(interval, job, true, times, STATUS_READY)
   104  }
   105  
   106  // 延迟添加循环任务。
   107  func (t *Timer) DelayAdd(delay time.Duration, interval time.Duration, job JobFunc) {
   108  	t.AddOnce(delay, func() {
   109  		t.Add(interval, job)
   110  	})
   111  }
   112  
   113  // 延迟添加循环任务, 支持完整的参数。
   114  func (t *Timer) DelayAddEntry(delay time.Duration, interval time.Duration, job JobFunc, singleton bool, times int, status int) {
   115  	t.AddOnce(delay, func() {
   116  		t.AddEntry(interval, job, singleton, times, status)
   117  	})
   118  }
   119  
   120  // 延迟添加单例循环任务
   121  func (t *Timer) DelayAddSingleton(delay time.Duration, interval time.Duration, job JobFunc) {
   122  	t.AddOnce(delay, func() {
   123  		t.AddSingleton(interval, job)
   124  	})
   125  }
   126  
   127  // 延迟添加只运行一次的循环任务
   128  func (t *Timer) DelayAddOnce(delay time.Duration, interval time.Duration, job JobFunc) {
   129  	t.AddOnce(delay, func() {
   130  		t.AddOnce(interval, job)
   131  	})
   132  }
   133  
   134  // 延迟添加只运行一次的循环任务
   135  func (t *Timer) DelayAddTimes(delay time.Duration, interval time.Duration, times int, job JobFunc) {
   136  	t.AddOnce(delay, func() {
   137  		t.AddTimes(interval, times, job)
   138  	})
   139  }
   140  
   141  // 启动定时器
   142  func (t *Timer) Start() {
   143  	t.status.Set(STATUS_RUNNING)
   144  }
   145  
   146  // 定制定时器
   147  func (t *Timer) Stop() {
   148  	t.status.Set(STATUS_STOPPED)
   149  }
   150  
   151  // 关闭定时器
   152  func (t *Timer) Close() {
   153  	t.status.Set(STATUS_CLOSED)
   154  }
   155  
   156  // 添加定时任务
   157  func (t *Timer) doAddEntry(interval time.Duration, job JobFunc, singleton bool, times int, status int) *Entry {
   158  	return t.wheels[t.getLevelByIntervalMs(interval.Nanoseconds()/1e6)].addEntry(interval, job, singleton, times, status)
   159  }
   160  
   161  // 添加定时任务,给定父级Entry, 间隔参数参数为毫秒数.
   162  func (t *Timer) doAddEntryByParent(interval int64, parent *Entry) *Entry {
   163  	return t.wheels[t.getLevelByIntervalMs(interval)].addEntryByParent(interval, parent)
   164  }
   165  
   166  // 根据intervalMs计算添加的分层索引
   167  func (t *Timer) getLevelByIntervalMs(intervalMs int64) int {
   168  	pos, cmp := t.binSearchIndex(intervalMs)
   169  	switch cmp {
   170  	// intervalMs与最后匹配值相等, 不添加到匹配得层,而是向下一层添加
   171  	case 0:
   172  		fallthrough
   173  	// intervalMs比最后匹配值小
   174  	case -1:
   175  		i := pos
   176  		for ; i > 0; i-- {
   177  			if intervalMs > t.wheels[i].intervalMs && intervalMs <= t.wheels[i].totalMs {
   178  				return i
   179  			}
   180  		}
   181  		return i
   182  
   183  	// intervalMs比最后匹配值大
   184  	case 1:
   185  		i := pos
   186  		for ; i < t.length-1; i++ {
   187  			if intervalMs > t.wheels[i].intervalMs && intervalMs <= t.wheels[i].totalMs {
   188  				return i
   189  			}
   190  		}
   191  		return i
   192  	}
   193  	return 0
   194  }
   195  
   196  // 二分查找当前任务可以添加的时间轮对象索引.
   197  func (t *Timer) binSearchIndex(n int64) (index int, result int) {
   198  	min := 0
   199  	max := t.length - 1
   200  	mid := 0
   201  	cmp := -2
   202  	for min <= max {
   203  		mid = int((min + max) / 2)
   204  		switch {
   205  		case t.wheels[mid].intervalMs == n:
   206  			cmp = 0
   207  		case t.wheels[mid].intervalMs > n:
   208  			cmp = -1
   209  		case t.wheels[mid].intervalMs < n:
   210  			cmp = 1
   211  		}
   212  		switch cmp {
   213  		case -1:
   214  			max = mid - 1
   215  		case 1:
   216  			min = mid + 1
   217  		case 0:
   218  			return mid, cmp
   219  		}
   220  	}
   221  	return mid, cmp
   222  }