按時間間隔的觸發器(一)

相關文章

cron按時間格式觸發器(二)

在遊戲開發中,很多場景會用到時間間隔觸發的情況。例如:

1、超時處理

2、循環觸發某些處理

3、延後處理等

下面的代碼是一個完整的觸發器應用代碼,通過

New_tickTimerLink()創建一個任務管理器

Add函數用於添加一個延遲任務,包括(延遲時間,次數,任務接口實現)

關鍵點:

1、任務需要實現TimeJob接口

2、Remove函數需要自己補充實現,restart函數留做思考(例子中並沒有真的實現restart)

3、任何以服務形式存在的組件(這裏指tickTimerLink),在設計時需要保證服務不宕機。所以在觸發處理時,使用go關鍵字執行。(go關鍵字後的函數體如出現panic不會導致服務報錯)

4、對定時器的集中管理和鏈式處理(每次新增或執行,只需要關注鏈表頭並處理)

5、細緻觀察會發現,採用的簡單粗暴的隊尾開始對比插入的辦法,之所以這樣做,是因爲在遊戲開發中,延遲需要一般會大量出現類似時間的情況。我們可以在服務器初始化過程中,New_tickTimerLink多次,並將他們分類到不同的需求中(或直接按照延遲時間進行分組)

package timer

import (
	"sync"
	"sync/atomic"
	"time"
)

//時間任務接口
type TimeJob interface {
	RunTimeJob() //執行任務
}

type TickTimer struct {
	Id     uint64         //自己的id
	Durt   time.Duration  //間隔時間
	Times  int            //次數 <=0無限循環
	target TimeJob        //任務
	st     int64          //執行時的服務器時間
	pre    *TickTimer     //上一個
	next   *TickTimer     //下一個
	group  *tickTimerLink //所屬定時器
	remain int            //剩餘次數
}

//觸發器定時器,可自行構建與釋放
//推薦每個地圖至少擁有一個自己的TickTimerLink已減少過多定時器之間的競爭
//技能等相關不要使用定時器(非公共部分,用時間做驗證即可)
/*
一組排序的tick
每個tickTimerLink擁有自己的id自增
*/
type tickTimerLink struct {
	idInc      uint64     //自增組id
	stopChan   chan bool  //關閉用的定時器
	sync.Mutex            //同步鎖
	Head       *TickTimer //頭
	Tail       *TickTimer //尾
}

//@return nil
func New_tickTimerLink() *tickTimerLink {
	link := &tickTimerLink{}
	link.stopChan = make(chan bool)
	link.run()
	return link
}

//添加一個定時任務
//@return nil
func (this *tickTimerLink) Add(t time.Duration, times int, job TimeJob) *TickTimer {
	tid := atomic.AddUint64(&this.idInc, 1)
	stime := time.Now().UnixNano()
	tick := &TickTimer{
		Id:     tid,
		Durt:   t,
		Times:  times,
		target: job,
		st:     stime + int64(t),
		group:  this,
	}
	if tick.Times <= 0 {
		tick.remain = -1
	} else {
		tick.remain = tick.Times
	}
	this.Lock()
	if this.insert(tick) {
		this.Unlock()
		this.restart()
		return tick
	}
	this.Unlock()
	return tick
}

//添加一個定時器
//@return false
func (this *tickTimerLink) insert(t *TickTimer) bool {
	t.pre, t.next = nil, nil
	if this.Tail == nil { //空隊列
		this.Tail = t
		this.Head = t
		return true
	}
	now := this.Tail
	for now != nil && now.st > t.st {
		now = now.pre
	}
	if now == nil { //插入到表頭
		this.Head.pre = t
		t.next = this.Head
		this.Head = t
		return true
	} else {
		if now == this.Tail { //插入到尾
			t.pre = now
			now.next = t
			this.Tail = t
		} else { //插入到中間
			next := now.next
			t.pre = now
			t.next = next
			next.pre = t
			now.next = t
		}
	}
	return false
}

//刪除一個定時器
func (this *tickTimerLink) remove(t *TickTimer) {
	//TODO
}

//移除一個頭
//@return nil
func (this *tickTimerLink) shift() *TickTimer {
	if this.Head == nil {
		return nil
	}
	h := this.Head
	this.Head = this.Head.next
	if this.Head != nil {
		this.Head.pre = nil
	} else {
		this.Tail = nil
	}
	return h
}

//停止當前得
func (this *tickTimerLink) restart() {
	this.stopChan <- false
}

//重啓定時器
func (this *tickTimerLink) run() {
	go func() {
		for {
			nowTime := time.Now().UnixNano()
			watiTime := nowTime
			this.Lock()
			if this.Head != nil {
				watiTime = this.Head.st - nowTime
				for watiTime <= 0 { //如果已經超時
					tc := this.shift()
					if tc.remain < 0 {
						tc.st = nowTime + int64(tc.Durt)
						this.insert(tc)
					} else {
						tc.remain--
						if tc.remain > 0 {
							tc.st = nowTime + int64(tc.Durt)
							this.insert(tc)
						}
					}
					go tc.target.RunTimeJob()
					if this.Head != nil {
						watiTime = this.Head.st - nowTime
					} else {
						break
					}
				}
			}
			if this.Head == nil {
				watiTime = nowTime
			}
			this.Unlock()
			ticker := time.NewTicker(time.Duration(watiTime))
			select {
			case <-ticker.C:
				ticker.Stop()
				ticker = nil
			case flag := <-this.stopChan:
				ticker.Stop()
				ticker = nil
				if flag {
					return
				}
			}
		}
	}()
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章