成人性生交大片免费看视频r_亚洲综合极品香蕉久久网_在线视频免费观看一区_亚洲精品亚洲人成人网在线播放_国产精品毛片av_久久久久国产精品www_亚洲国产一区二区三区在线播_日韩一区二区三区四区区区_亚洲精品国产无套在线观_国产免费www

主頁 > 知識庫 > Golang 定時器(Timer 和 Ticker),這篇文章就夠了

Golang 定時器(Timer 和 Ticker),這篇文章就夠了

熱門標(biāo)簽:利用地圖標(biāo)注位置 地圖區(qū)域圖標(biāo)注后導(dǎo)出 谷歌美發(fā)店地圖標(biāo)注 官渡電銷外呼管理系統(tǒng)怎么收費 400開頭電話怎樣申請 江蘇呼叫中心外呼系統(tǒng)有效果嗎 貴州電話智能外呼系統(tǒng) 杭州人工智能電銷機器人費用 赤峰電銷

定時器是什么

Golang 原生 time 包下可以用來執(zhí)行一些定時任務(wù)或者是周期性的任務(wù)的一個工具

本文基于 Go 1.14,如果以下文章有哪里不對或者問題的地方,歡迎討論學(xué)習(xí)

定時器的日常使用

Timer 相關(guān)

func NewTimer(d Duration) *Timer
func (t *Timer) Reset(d Duration) bool
func (t *Timer) Stop() bool
func After(d Duration) -chan Time
func AfterFunc(d Duration, f func()) *Timer

func main() {
  timer := time.NewTimer(3 * time.Second)
  select {
  case -timer.C:
   fmt.Println("3秒執(zhí)行任務(wù)")
  }
  timer.Stop() // 這里來提高 timer 的回收
}

func main() {
  tChannel := time.After(3 * time.Second) // 其內(nèi)部其實是生成了一個 timer
  select {
  case -tChannel:
   fmt.Println("3秒執(zhí)行任務(wù)")
  }
}

func main() {
 timer := time.NewTimer(3 * time.Second)
 for {
  timer.Reset(4 * time.Second) // 這樣來復(fù)用 timer 和修改執(zhí)行時間
  select {
  case -timer.C:
   fmt.Println("每隔4秒執(zhí)行任務(wù)")
  }
 }
}

注意事項:

錯誤使用:time.After 這里會不斷生成 timer,雖然最終會回收,但是會造成無意義的cpu資源消耗 

func main() {
  for {
   select {
   case -time.After(3 * time.Second): 
     fmt.Println("每隔3秒執(zhí)行一次")
   }
  }
}

正確使用:

func main() {
  timer := time.NewTimer(3 * time.Second) 
  for {
   timer.Reset(3 * time.Second) // 這里復(fù)用了 timer
   select {
   case -timer.C:
     fmt.Println("每隔3秒執(zhí)行一次")
   }
  }
}

Ticker 相關(guān)

func NewTicker(d Duration) *Ticker
func Tick(d Duration) -chan Time
func (t *Ticker) Stop()

func main() {
 ticker := time.NewTicker(3 * time.Second)
 for range ticker.C {
  fmt.Print("每隔3秒執(zhí)行任務(wù)")
 }
 ticker.Stop()
}

錯誤使用:

func main() {
  for {
   select {
   case -time.Tick(3 * time.Second): // 這里會不斷生成 ticker,而且 ticker 會進(jìn)行重新調(diào)度,造成泄漏(后面源碼會有解析)
     fmt.Println("每隔3秒執(zhí)行一次")
   }
  }
}

定時器源碼分析

我先給出涉及到過程的相關(guān)結(jié)構(gòu)體(!??!要注意 Timer 和 timer 的不同)

type Timer struct {
  C -chan Time 
  r runtimeTimer
}
​
// Ticker 的結(jié)構(gòu)與 Timer 一致
type Ticker struct {
 C -chan Time  // 這里就是返回的 channel
 r runtimeTimer
}
​
// If this struct changes, 
// adjust ../time/sleep.go:/runtimeTimer.
// 這里是與 runtimeTimer 對應(yīng)的
type timer struct {
 pp puintptr   // 對應(yīng)的當(dāng)前 P 的指針
 when  int64  // 需要執(zhí)行的時間
 period int64  // 周期,Ticker 會使用
 f   func(interface{}, uintptr) // 給 channel 推送信息的方式
 arg  interface{} // 與 f 相關(guān)的第一個參數(shù),可以看下面 Ticker 的例子
 seq  uintptr   // 與 f 相關(guān)的第二個參數(shù)(后續(xù)我們可以看到)
 nextwhen int64   // 下次執(zhí)行的時候
 status uint32   // 當(dāng)前狀態(tài)
}
​
​
// P 結(jié)構(gòu)體中的相關(guān) timer 的字段
type p struct {
 ...

 timersLock mutex // 一個 P 中保證 timers 同步鎖
​
 timers []*timer // timers 是四叉小頂堆(后續(xù)代碼會有說明)
​
 numTimers uint32 // timer 的數(shù)量
​
 adjustTimers uint32 // 需要調(diào)整的 timer 的數(shù)量
​
 deletedTimers uint32 // 需要刪除的 timer 的數(shù)量

 ...
}

我們以 Ticker 為切入點

func NewTicker(d Duration) *Ticker {
 if d = 0 {
  panic(errors.New("non-positive interval for NewTicker"))
 }
 c := make(chan Time, 1)
 t := Ticker{
  C: c,
  r: runtimeTimer{
   when:  when(d),//當(dāng)前時間+d的時間,可看下面
   period: int64(d),//執(zhí)行周期
   f:   sendTime,
   arg:  c, // 就是 f 中第一個參數(shù)
  },
 }
 startTimer(t.r)
 return t
}
​
func when(d Duration) int64 {
 if d = 0 {
  return runtimeNano()
 }
 t := runtimeNano() + int64(d) //當(dāng)前時間加上需要等待的時間
 if t  0 {
  t = 163 - 1 // math.MaxInt64
 }
 return t
}
​
func sendTime(c interface{}, seq uintptr) {
 select {
 case c.(chan Time) - Now():
 default:
 }
}

從 NewTicker 中我們可以看到,開始執(zhí)行是在 startTimer(),我們進(jìn)去看下

addtimer

// startTimer adds t to the timer heap.
// 這里已經(jīng)說明了 timers 是一種堆的數(shù)據(jù)結(jié)構(gòu),由于是定時器,
// 最近的最先執(zhí)行,所以猜測以 when 來判斷的小頂堆
func startTimer(t *timer) {
  addtimer(t)
}
​
func addtimer(t *timer) {
 if t.when  0 {
  t.when = maxWhen //maxWhen 是 163 - 1
 }
 if t.status != timerNoStatus {
  throw("addtimer called with initialized timer")
 }
 t.status = timerWaiting
​
 when := t.when
​
 pp := getg().m.p.ptr()
 lock(pp.timersLock) 
 cleantimers(pp) // 根據(jù) timer 刪除和修改狀態(tài)進(jìn)行操作,可以看下面源碼相關(guān)
 doaddtimer(pp, t)// 添加 timer 的到 timers 堆
 unlock(pp.timersLock)
​
 wakeNetPoller(when)
}

// 清理 timers 的源碼部分
func cleantimers(pp *p) {
 for {
  if len(pp.timers) == 0 {
   return
  }
  t := pp.timers[0]// 從 0 開始,即最小的堆頂開始
  if t.pp.ptr() != pp {
   throw("cleantimers: bad p")
  }
  switch s := atomic.Load(t.status); s {
  case timerDeleted: 
   if !atomic.Cas(t.status, s, timerRemoving) {// status 變更為 timerRemoving
    continue
   }

   dodeltimer0(pp) // 這里是刪除 timer 的關(guān)鍵部分,刪除堆頂?shù)牟糠植⒄{(diào)整

   if !atomic.Cas(t.status, timerRemoving, timerRemoved) { // stauts 變更為 timerRemoved
    badTimer() // 這里就是 throw 一個異常
   }
   atomic.Xadd(pp.deletedTimers, -1)
  case timerModifiedEarlier, timerModifiedLater: 
   if !atomic.Cas(t.status, s, timerMoving) { // stauts 變更為 timerMoving
    continue
   }
   t.when = t.nextwhen // 將執(zhí)行時間設(shè)置為其下次執(zhí)行的時候

   // -----刪除堆頂位置,并按照其新的執(zhí)行時間加入到對應(yīng)的位置
   dodeltimer0(pp) 
   doaddtimer(pp, t) // 添加 timer 的關(guān)鍵部分
   // ------------

   if s == timerModifiedEarlier {
    atomic.Xadd(pp.adjustTimers, -1)
   }
   if !atomic.Cas(t.status, timerMoving, timerWaiting) {
    badTimer()
   }
  default:
   return
  }
 }
}
​
// timer 刪除的源碼部分
//(擴充:func dodeltimer(pp *p, i int) 意思就是刪除指定所索引
// 的位置,然后恢復(fù)小頂堆的結(jié)構(gòu),可以看源碼,就不解釋了)
func dodeltimer0(pp *p) {
 if t := pp.timers[0]; t.pp.ptr() != pp {
  throw("dodeltimer0: wrong P")
 } else {
  t.pp = 0 // 這里將指針情況
 }

 // --- 將堆的最后一位 timer 放到堆頂,然后清空最后一位的空間,然后向下調(diào)整---
 last := len(pp.timers) - 1 
 if last > 0 {
  pp.timers[0] = pp.timers[last]
 }
 pp.timers[last] = nil
 pp.timers = pp.timers[:last]
 if last > 0 {
  siftdownTimer(pp.timers, 0)//向下調(diào)整的核心部分
 }
 // ---------------------

 updateTimer0When(pp) //更新當(dāng)前 p 的最先執(zhí)行 timer 的執(zhí)行時間
 atomic.Xadd(pp.numTimers, -1)
}
​
func updateTimer0When(pp *p) {
 if len(pp.timers) == 0 {
  atomic.Store64(pp.timer0When, 0)
 } else {
  atomic.Store64(pp.timer0When, uint64(pp.timers[0].when))
 }
}
​
// timer 增加的源碼部分
func doaddtimer(pp *p, t *timer) {
 ... 
 if t.pp != 0 {
  throw("doaddtimer: P already set in timer")
 }
 t.pp.set(pp)

 // --- 將 timer 放置到堆的最后一位,然后向上調(diào)整 ---
 i := len(pp.timers)
 pp.timers = append(pp.timers, t)
 siftupTimer(pp.timers, i)// 向上調(diào)整的核心部分
 // ---------------------------

 if t == pp.timers[0] {
  atomic.Store64(pp.timer0When, uint64(t.when))
 }
 atomic.Xadd(pp.numTimers, 1)
}

當(dāng)我們已知 timers 是小頂堆的數(shù)據(jù)結(jié)構(gòu)(滿足“當(dāng)前位置的值小于等于父位置的值“即可,實現(xiàn)方式使用數(shù)組,由下面代碼可以知道是四叉小頂堆,結(jié)構(gòu)如下圖)的情況后,接下來看堆向上或者向下調(diào)整的細(xì)節(jié)部分

// timers 堆的向上調(diào)整
func siftupTimer(t []*timer, i int) {
  ...
  when := t[i].when
  tmp := t[i]
  for i > 0 {
   p := (i - 1) / 4  // 由這里可以看出,堆的節(jié)點長度是4
   if when >= t[p].when { 
     break
   }

   // --- 向上進(jìn)行調(diào)整,即父節(jié)點下移,當(dāng)前節(jié)點上移 ---
   t[i] = t[p]
   i = p
   //向上進(jìn)行調(diào)整
  }
  if tmp != t[i] {
   t[i] = tmp
  }
}
​
//timers 堆的向下調(diào)整
func siftdownTimer(t []*timer, i int) {
 n := len(t)
 if i >= n {
  badTimer()
 }
 when := t[i].when
 tmp := t[i]
 for {

  // --- 以下部分就是找到當(dāng)前4個節(jié)點中最小的那個值和在數(shù)組的位置 -----
  c := i*4 + 1 // 這里是子節(jié)點最左邊的節(jié)點
  c3 := c + 2 // 這里是子節(jié)點第三個節(jié)點
  if c >= n {
   break
  }
  w := t[c].when
  if c+1  n  t[c+1].when  w {
   w = t[c+1].when
   c++
  }
  if c3  n {
   w3 := t[c3].when
   if c3+1  n  t[c3+1].when  w3 {
    w3 = t[c3+1].when
    c3++
   }
   if w3  w {
    w = w3
    c = c3
   }
  }
  //---------------------------------

  if w >= when {
   break
  }

  // --- 向下進(jìn)行調(diào)整,即子節(jié)點上移,當(dāng)前節(jié)點下移 ---
  t[i] = t[c] 
  i = c
  // ---------------

 }
 if tmp != t[i] {
  t[i] = tmp
 }
}

既然已經(jīng)知道timer放到四叉小頂堆,那 timer 是怎么執(zhí)行的呢?接下來就是定時器的核心部分入口 runtimer()

runtimer

// 這里執(zhí)行的前提是當(dāng)前 P 的 timesLock 已經(jīng)鎖了,所以不用擔(dān)心并發(fā)問題
func runtimer(pp *p, now int64) int64 {
  for {
   t := pp.timers[0] //找到 timers 堆的堆頂,為最先執(zhí)行的 timer
   if t.pp.ptr() != pp {
     throw("runtimer: bad p")
   }
   switch s := atomic.Load(t.status); s {
   case timerWaiting:
     if t.when > now { //如果還沒到時間,則返回調(diào)用的時間
      return t.when
     }
​
     if !atomic.Cas(t.status, s, timerRunning) {
      continue
     }
     runOneTimer(pp, t, now)// 這里是執(zhí)行timer的核心
     return 0
​
   case timerDeleted:
     if !atomic.Cas(t.status, s, timerRemoving) {
      continue
     }
     dodeltimer0(pp) //刪除 timers 堆頂?shù)?timer
     if !atomic.Cas(t.status, timerRemoving, timerRemoved) {
      badTimer()
     }
     atomic.Xadd(pp.deletedTimers, -1)
     if len(pp.timers) == 0 {
      return -1
     }
​
   case timerModifiedEarlier, timerModifiedLater:
     if !atomic.Cas(t.status, s, timerMoving) {
      continue
     }
     //刪除堆頂?shù)奈恢?,調(diào)整 timer 到最新的時間,以及進(jìn)行重新調(diào)整
     t.when = t.nextwhen
     dodeltimer0(pp)
     doaddtimer(pp, t)
     if s == timerModifiedEarlier {
      atomic.Xadd(pp.adjustTimers, -1)
     }
     if !atomic.Cas(t.status, timerMoving, timerWaiting) {
      badTimer()
     }
​
   case timerModifying:
     osyield()
   case timerNoStatus, timerRemoved:
     badTimer()
   case timerRunning, timerRemoving, timerMoving:
     badTimer()
   default:
     badTimer()
   }
  }
}

因此我們知道了執(zhí)行的核心流程是 runOneTimer()

runOneTimer

// 由于是 runtimer 進(jìn)行調(diào)用,因此也線程安全
func runOneTimer(pp *p, t *timer, now int64) {
 ...
  f := t.f
  arg := t.arg
  seq := t.seq
​
  if t.period > 0 { //如果有周期,則算出下次 timer 執(zhí)行的時間,并加入到對應(yīng)的位置(這里就是 Ticker 和 Timer 的區(qū)別)
   delta := t.when - now
   t.when += t.period * (1 + -delta/t.period)
   siftdownTimer(pp.timers, 0)// 將四叉小頂堆向下調(diào)整
   if !atomic.Cas(t.status, timerRunning, timerWaiting) {
     badTimer()
   }
   updateTimer0When(pp)//更新當(dāng)前 P 的最先的 timer 的執(zhí)行時間
  } else { 
  // 從堆頂位置上刪除 timer,并調(diào)整
   dodeltimer0(pp)
   if !atomic.Cas(t.status, timerRunning, timerNoStatus) {
     badTimer()
   }
  }
  ...
​
  unlock(pp.timersLock)
​
  f(arg, seq) // 執(zhí)行對應(yīng)的 f,這里就是我們 Timer.C 來的地方
​
  lock(pp.timersLock)
​
  ...
}

從 runtimer 的調(diào)用,我們知道執(zhí)行的入口是 checkTimers(),我們詳細(xì)看下

checkTimers

我們可以看下圖,由下圖可知,是通過 Go 里面的調(diào)度中去尋找可執(zhí)行的 timer  

我們看下 checkTimers 做了什么

func checkTimers(pp *p, now int64) (rnow, pollUntil int64, ran bool) {
  if atomic.Load(pp.adjustTimers) == 0 {// 如果沒有需要可調(diào)整的,則直接返回最先執(zhí)行 timer 的時間
   next := int64(atomic.Load64(pp.timer0When))
   if next == 0 {
     return now, 0, false
   }
   if now == 0 {
     now = nanotime()
   }
   if now  next { // 表示還沒有到執(zhí)行時間
     if pp != getg().m.p.ptr() || int(atomic.Load(pp.deletedTimers)) = int(atomic.Load(pp.numTimers)/4) { //且要刪除的 Timer數(shù)量小于 Timer總數(shù)的1/4
      return now, next, false
     }
   }
  }
​
  lock(pp.timersLock)
​
  adjusttimers(pp)// 可以看下面的源碼解析,當(dāng)前 p 上的所有 timers 的狀態(tài),該刪除的刪了,該調(diào)整的調(diào)整
​
  rnow = now
  if len(pp.timers) > 0 {
   if rnow == 0 {
     rnow = nanotime()
   }
   for len(pp.timers) > 0 {
     if tw := runtimer(pp, rnow); tw != 0 { // 通過 runtimer(可以看上面的源碼解析) 開始調(diào)用
      if tw > 0 {
        pollUntil = tw
      }
      break
     }
     ran = true
   }
  }

  // 如果可刪除的 Timers 大于 Timer總數(shù)量的1/4,則進(jìn)行刪除(因為上面執(zhí)行了 runtimer)
  if pp == getg().m.p.ptr()  int(atomic.Load(pp.deletedTimers)) > len(pp.timers)/4 {
   clearDeletedTimers(pp)
  }
​
  unlock(pp.timersLock)
​
  return rnow, pollUntil, ran
}

adjusttimers

func adjusttimers(pp *p) {
  if len(pp.timers) == 0 {
   return
  }
  if atomic.Load(pp.adjustTimers) == 0 { // 如果需要調(diào)整的 Timer 為 0,則直接返回
   ...
   return
  }
  var moved []*timer
loop:
  for i := 0; i  len(pp.timers); i++ {
   t := pp.timers[i]
   if t.pp.ptr() != pp {
     throw("adjusttimers: bad p")
   }
   switch s := atomic.Load(t.status); s {
   case timerDeleted: // 這里就是將部分需要刪除的 Timer 給清理掉
     if atomic.Cas(t.status, s, timerRemoving) {
      dodeltimer(pp, i)
      if !atomic.Cas(t.status, timerRemoving, timerRemoved) {
        badTimer()
      }
      atomic.Xadd(pp.deletedTimers, -1)
      i--
     }
   case timerModifiedEarlier, timerModifiedLater: // 把需要調(diào)整 Timer 放到 moved 中,然后刪除當(dāng)前堆的數(shù)據(jù)進(jìn)行堆調(diào)整,后續(xù)將 moved 通過 addAdjustedTimers 添加
     if atomic.Cas(t.status, s, timerMoving) {
      t.when = t.nextwhen
      dodeltimer(pp, i)
      moved = append(moved, t)
      if s == timerModifiedEarlier {
        if n := atomic.Xadd(pp.adjustTimers, -1); int32(n) = 0 {
         break loop
        }
      }
      i--
     }
   case timerNoStatus, timerRunning, timerRemoving, timerRemoved, timerMoving:
     badTimer()
   case timerWaiting:
   case timerModifying:
     osyield()
     i--
   default:
     badTimer()
   }
  }
​
  if len(moved) > 0 {
   addAdjustedTimers(pp, moved) // 這里就是將需要調(diào)整的 timer 重新添加進(jìn)來
  }
​
  ...
}

addAdjustedTimers

func addAdjustedTimers(pp *p, moved []*timer) {
  for _, t := range moved {
   doaddtimer(pp, t)// 上文有源碼解析
   if !atomic.Cas(t.status, timerMoving, timerWaiting) {
     badTimer()
   }
  }
}

clearDeletedTimers

func clearDeletedTimers(pp *p) { 
  cdel := int32(0)
  cearlier := int32(0)
  to := 0
  changedHeap := false
  timers := pp.timers
nextTimer:
  for _, t := range timers { 
   for {
     switch s := atomic.Load(t.status); s {
     case timerWaiting: 
      if changedHeap {
        timers[to] = t
        siftupTimer(timers, to)
      }
      to++
      continue nextTimer
     case timerModifiedEarlier, timerModifiedLater: // 將 timer 狀態(tài)調(diào)整成 timeWaiting,將其放至其正確的執(zhí)行時間位置
      if atomic.Cas(t.status, s, timerMoving) {
        t.when = t.nextwhen
        timers[to] = t
        siftupTimer(timers, to)
        to++
        changedHeap = true
        if !atomic.Cas(t.status, timerMoving, timerWaiting) {
         badTimer()
        }
        if s == timerModifiedEarlier {
         cearlier++
        }
        continue nextTimer
      }
     case timerDeleted: // 將 timerDeleted 轉(zhuǎn)變成 timerRemoved,然后從 timers 堆中刪掉(在當(dāng)前函數(shù)后面可以看出)
      if atomic.Cas(t.status, s, timerRemoving) {
        t.pp = 0
        cdel++
        if !atomic.Cas(t.status, timerRemoving, timerRemoved) {
         badTimer()
        }
        changedHeap = true
        continue nextTimer
      }
     case timerModifying:
      osyield()
     case timerNoStatus, timerRemoved:
      badTimer()
     case timerRunning, timerRemoving, timerMoving:
      badTimer()
     default:
      badTimer()
     }
   }
  }
​
 // 在這里對于剩余的空間 設(shè)置為 nil 操作(垃圾回收方便)
  for i := to; i  len(timers); i++ {
   timers[i] = nil
  }
​
  atomic.Xadd(pp.deletedTimers, -cdel)
  atomic.Xadd(pp.numTimers, -cdel)
  atomic.Xadd(pp.adjustTimers, -cearlier)
​
 // 在這里進(jìn)行一次大清理
  timers = timers[:to]
  pp.timers = timers
  updateTimer0When(pp)
​
  ...
}

大致執(zhí)行的情況我們看好了,那我們接下來看 Stop() 的源碼部分

deltimer

func (t *Ticker) Stop() {
  stopTimer(t.r)
}
​
func stopTimer(t *timer) bool {
  return deltimer(t)
}
​
func deltimer(t *timer) bool {
  for {
   switch s := atomic.Load(t.status); s {
   case timerWaiting, timerModifiedLater: //將 timer 的 status變更為 timerDeleted ,并deletedTimers 加 1
     mp := acquirem()
     if atomic.Cas(t.status, s, timerModifying) {
      tpp := t.pp.ptr()
      if !atomic.Cas(t.status, timerModifying, timerDeleted) { //
        badTimer()
      }
      releasem(mp)
      atomic.Xadd(tpp.deletedTimers, 1)
      return true
     } else {
      releasem(mp)
     }
   case timerModifiedEarlier: //將 timer 的 status 變更為 timerDeleted,然后 adjustTimers 減 1,deletedTimers 加 1
     mp := acquirem()
     if atomic.Cas(t.status, s, timerModifying) {
      tpp := t.pp.ptr()
      atomic.Xadd(tpp.adjustTimers, -1)
      if !atomic.Cas(t.status, timerModifying, timerDeleted) {
        badTimer()
      }
      releasem(mp)
      atomic.Xadd(tpp.deletedTimers, 1)
      return true
     } else {
      releasem(mp)
     }
   case timerDeleted, timerRemoving, timerRemoved:
     return false
   case timerRunning, timerMoving:
     osyield()
   case timerNoStatus:
     return false
   case timerModifying:
     osyield()
   default:
     badTimer()
   }
  }
}

后續(xù)調(diào)度中, Timer 的狀態(tài)可以從 timerDeleted 設(shè)置成 timerRemoved 并從 timers 堆中去除(注意,這里用了“可以”,可以看上面的狀態(tài)圖了解)

在復(fù)用 Timer 的時候,我們經(jīng)常使用 Reset(),我們來看下源碼部分是怎么樣的

modtimer

func (t *Timer) Reset(d Duration) bool {
  if t.r.f == nil {
   panic("time: Reset called on uninitialized Timer")
  }
  w := when(d)
  active := stopTimer(t.r) // 這里我們上面源碼解釋過了,即將當(dāng)前的 timer 的 status 設(shè)置成 timerDeleted
  resetTimer(t.r, w)
  return active
}
​
func resettimer(t *timer, when int64) {
  modtimer(t, when, t.period, t.f, t.arg, t.seq)
}
​
func modtimer(t *timer, when, period int64, f func(interface{}, uintptr), arg interface{}, seq uintptr) {
  if when  0 {
   when = maxWhen
  }
​
  status := uint32(timerNoStatus)
  wasRemoved := false
  var mp *m
loop:
  for { 
   // 主要的目的就是將當(dāng)前的 timer 的狀態(tài)設(shè)置成 timerModifying
   switch status = atomic.Load(t.status); status {
   case timerWaiting, timerModifiedEarlier, timerModifiedLater:
     mp = acquirem()
     if atomic.Cas(t.status, status, timerModifying) {
      break loop
     }
     releasem(mp)
   case timerNoStatus, timerRemoved:
     mp = acquirem()
     if atomic.Cas(t.status, status, timerModifying) {
      wasRemoved = true
      break loop
     }
     releasem(mp)
   case timerDeleted:
     mp = acquirem()
     if atomic.Cas(t.status, status, timerModifying) {
      atomic.Xadd(t.pp.ptr().deletedTimers, -1)
      break loop
     }
     releasem(mp)
   case timerRunning, timerRemoving, timerMoving:
     osyield()
   case timerModifying:
     osyield()
   default:
     badTimer()
   }
  }
​
  t.period = period
  t.f = f
  t.arg = arg
  t.seq = seq
​
  if wasRemoved { // 如果是已經(jīng)被移除的,則要重新加回到 timers 中,且狀態(tài)變更為 timerWaiting
   t.when = when
   pp := getg().m.p.ptr()
   lock(pp.timersLock)
   doaddtimer(pp, t)
   unlock(pp.timersLock)
   if !atomic.Cas(t.status, timerModifying, timerWaiting) {
     badTimer()
   }
   releasem(mp)
   wakeNetPoller(when)
  } else {
   t.nextwhen = when
​
   newStatus := uint32(timerModifiedLater)
   if when  t.when { //判斷這次新的時間是老的時間的前還是后
     newStatus = timerModifiedEarlier
   }
​
   adjust := int32(0)
   if status == timerModifiedEarlier {
     adjust--
   }
   if newStatus == timerModifiedEarlier {
     adjust++
   }
   if adjust != 0 {
     atomic.Xadd(t.pp.ptr().adjustTimers, adjust)
   }
​
   if !atomic.Cas(t.status, timerModifying, newStatus) { // 將當(dāng)前 timer 設(shè)置成 timerModifiedEarlier/timerModifiedEarlier
     badTimer()
   }
   releasem(mp)
​
   if newStatus == timerModifiedEarlier {
     wakeNetPoller(when)
   }
  }
}

 到此這篇關(guān)于Golang 定時器(Timer 和 Ticker),這篇文章就夠了的文章就介紹到這了,更多相關(guān)Golang 定時器內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

您可能感興趣的文章:
  • Golang定時器的2種實現(xiàn)方法與區(qū)別
  • golang定時器和超時的使用詳解
  • Golang中定時器的陷阱詳解
  • 用golang實現(xiàn)一個定時器任務(wù)隊列實例
  • golang中定時器cpu使用率高的現(xiàn)象詳析
  • golang time包下定時器的實現(xiàn)方法
  • Golang 定時器的終止與重置實現(xiàn)

標(biāo)簽:泰安 保定 河池 武漢 鷹潭 松原 宜春 黔西

巨人網(wǎng)絡(luò)通訊聲明:本文標(biāo)題《Golang 定時器(Timer 和 Ticker),這篇文章就夠了》,本文關(guān)鍵詞  Golang,定時器,Timer,和,Ticker,;如發(fā)現(xiàn)本文內(nèi)容存在版權(quán)問題,煩請?zhí)峁┫嚓P(guān)信息告之我們,我們將及時溝通與處理。本站內(nèi)容系統(tǒng)采集于網(wǎng)絡(luò),涉及言論、版權(quán)與本站無關(guān)。
  • 相關(guān)文章
  • 下面列出與本文章《Golang 定時器(Timer 和 Ticker),這篇文章就夠了》相關(guān)的同類信息!
  • 本頁收集關(guān)于Golang 定時器(Timer 和 Ticker),這篇文章就夠了的相關(guān)信息資訊供網(wǎng)民參考!
  • 推薦文章
    性欧美8khd高清极品| 成人黄色大片网站| 国产精品亚洲综合| 电影在线观看一区二区| 图片区 小说区 区 亚洲五月| 欧美精品尤物在线| 在线三级av| 国产在线麻豆精品观看| 色姑娘综合av| 色乱码一区二区三区网站| 免费97视频在线精品国自产拍| 久久精品中文字幕一区| 国产精品高潮呻吟久久av黑人| 91综合精品国产丝袜长腿久久| 欧美伊人久久大香线蕉综合69| 可以在线看的黄色网址| 亚洲成人精品在线观看| 香蕉久久国产av一区二区| 色婷婷av一区二区三区在线观看| 久久精品久久精品亚洲人| 极品美乳网红视频免费在线观看| 在线看片线路1| 国产成人亚洲欧美电影| 婷婷开心激情网| 波多野结衣在线网址| 国产精品一区二区三区在线播放| 国产福利视频一区二区| 999大胆视频| 日韩一区二区中文字幕| 蜜桃视频免费观看一区| 国产精品色视频| 成人综合久久| 日本爱爱爱视频| 色网视频在线| 国产日韩精品电影| 国产女同性恋一区二区| 久久97久久97精品免视看秋霞| 91av免费观看91av精品在线| 亚洲a∨精品一区二区三区导航| 久久久天天操| 99久久99久久精品国产片| 国产精品理论在线| 国产探花在线精品一区二区| 国内精品视频一区| 欧美一区深夜视频| 色综合欧美在线视频区| 悠悠资源av网站| 欧美日韩精品是欧美日韩精品| 香蕉521av成人网| 久久久久久毛片免费看| 国产小视频在线高清播放| 亚洲自拍另类欧美丝袜| 粉嫩虎白女毛片人体| 丰满少妇乱子伦精品看片| 国产日韩欧美二区| 少妇献身老头系列| 欧美性猛交xxxx乱大交丰满| 亚洲第一主播视频| 国产精品久久精品国产| 亚洲一区二区三区视频| 成年人网站在线观看视频| 一个人在线观看免费视频www| 成人一区在线观看| 久热精品在线播放| 日韩av综合在线| 黄色aaa大片| 欧洲不卡av| 免费一级特黄特色毛片久久看| 国产香蕉在线观看| 青青草伊人久久| 亚洲最大av网| c++连点器| 欧美精品三级日韩久久| 高清不卡一区| 日韩精品一区国产麻豆| 欧洲不卡av| free性护士videos欧美| 精品69视频一区二区三区Q| 操欧美女人视频| 国产精品免费人成网站酒店| 国产精品综合av一区二区国产馆| 日韩精品五月天| 狠狠精品干练久久久无码中文字幕| 色中色在线视频| 亚洲影视一区二区| 9999在线视频| 丁香激情综合国产| 亚洲视频一区二区在线观看| 亚洲四色影视在线观看| 欧美精品做受xxx性少妇| 国产又黄又爽又猛免费app| 国产成人激情视频| 日韩黄色免费观看| 久久久久免费网| 亚洲视频香蕉人妖| 久久国产天堂福利天堂| 欧美乱大交xxxx| av网站在线免费看推荐| 在线视频欧美性高潮| 欧洲在线免费视频| 国产成人精品网| 二级片在线观看| 国产综合精品视频| 亚洲免费视频一区| 国产精品不卡一区二区三区| 中日韩午夜理伦电影免费| 亚洲乱码一区二区三区三上悠亚| 国产日韩一区欧美| 少妇一级淫免费观看| 鲁大师影院一区二区三区| 久久久精品蜜桃| 欧美三级理伦电影| 久久久久女教师免费一区| 亚洲一区在线观看免费观看电影高清| 中文字幕 欧美 日韩| 91爱爱小视频k| 成人免费福利| 午夜爽爽爽男女免费观看影院| 牛牛精品成人免费视频| 日韩欧美大片在线观看| 91国偷自产一区二区使用方法| 久久91亚洲| 国产激情99| 男人c女人视频| 日本久久久久久久久久| 欧美特黄视频| av官网在线| 日韩欧美一级特黄在线播放| 香蕉乱码成人久久天堂爱免费| 久久亚洲影院| 日本18视频网站| 午夜精品久久久久久久99热浪潮| 欧美多人乱p欧美4p久久| 香蕉成人啪国产精品视频综合网| 在线播放av中文字幕| 国产最新网站| 77777_亚洲午夜久久多人| 国产在线一区视频| 最近中文av字幕在线中文| 精品久久国产字幕高潮| 欧美性性性性性ⅹxxbbbb| 欧美成人在线直播| 97精品一区二区三区| 国产精品永久| 国产精品12345| 久久理论片午夜琪琪电影网| 日韩av在线天堂| 亚洲成色www8888| 乱中年女人av三区中文字幕| 色se01短视频永久免费| 性欧美暴力猛交另类hd| 久久精品亚洲精品国产欧美| 欧美黄色免费观看| 性xx无遮挡| 欧美视频免费在线| 我家有个日本女人| 日本女人一区二区三区| 日韩乱码人妻无码中文字幕久久| 精品网站999| 黄网站免费在线播放| 69xx绿帽三人行| 亚洲av激情无码专区在线播放| 美女又爽又黄免费视频| 欧美与动交zoz0z| 国产精品亚洲欧美导航| 久久国产夜色精品鲁鲁99| 国产精品久久久久久久久免费相片| 在线观看 中文字幕| 亚洲精品一区二三区| 日本wwww视频| jlzzjlzz欧美大全| 国产欧美日韩综合精品二区| 免费观看在线午夜影视| 色中色综合网| 日本黄色的视频| 日本h在线观看| 久久精视频免费在线久久完整在线看| 国产精品久久久久久久7电影| 男生草女生视频| 日韩一卡二卡在线观看| 国模gogo一区二区大胆私拍| 成人精品天堂一区二区三区| 日本少妇性高潮| 国产成a人亚洲精v品| 国产成人精品综合网站| 麻豆av免费在线观看| 免费在线稳定资源站| 轻轻草在线视频| 亚洲男同性恋视频| 阿v天堂2017| 久久精品影视| 免费人成又黄又爽又色| 日本午夜一本久久久综合| 久久久久香蕉视频| 蜜桃久久av一区| 亚洲香蕉成视频在线观看| 国产精品久久久一区二区| 亚洲3p在线观看| 久草青青在线观看| 香蕉97视频观看在线观看| 国产1区在线观看| 2021天堂中文幕一二区在线观| 日韩不卡在线观看日韩不卡视频| 精品五月天堂| 四虎4hu永久免费入口| 亚洲人成亚洲精品| 国产色综合天天综合网| 免费在线观看h片| 久久99久久99精品免视看婷婷| 国产aa视频| 精品视频一区二区在线| 99免费在线视频观看| 伊人精品在线观看| 亚洲18女电影在线观看| 性欧美69式xxxxx| 一区二区三区四区蜜桃| 在线码字幕一区| 成码无人av片在线观看网站| 爱高潮www亚洲精品| 在线日本成人| 国产亚洲在线播放| 国产精品国精产品一二| 久久婷婷国产综合国色天香| 97久久精品在线| 亚洲国产精品久久91精品| 第三区美女视频在线| 中文字幕一区二区人妻电影丶| 成人精品高清在线视频| 欧美三级伦理在线| 日韩欧美ww| 成视频免费在线看| 欧美黑人性受xxxx精品| 97在线精品国自产拍中文| 亚洲综合网站| 中文字幕日本精品| 日韩黄色a级片| 欧美一区二区播放| 影音先锋亚洲视频| 人人狠狠综合久久亚洲| 无码无遮挡又大又爽又黄的视频| 久久久亚洲福利精品午夜| 欧美在线xxx| a在线观看免费| 日本三级黄色大片| 中文字幕一区二区三区四区五区六区| 一级片a一级片| 亚洲乱码国产乱码精品天美传媒| 久久午夜av| 日本欧美一二三区| 麻豆一区二区三区| 伊人久久婷婷| 精品久久久久久久久国产字幕| 国模gogo一区二区大胆私拍| 一本大道av一区二区在线播放| 无码av免费一区二区三区试看| 久久99精品国产麻豆婷婷洗澡| www.在线观看av| 久久亚洲精品一区| 国产精品久久久久久久久久久久久久久久久久| 国产中文字幕视频在线观看| 精品综合久久久久| 色偷偷亚洲女人天堂观看欧| 日韩久久精品一区| 久久精品国产精品| h视频免费在线观看| 一级片黄色录像| 日韩欧美自拍偷拍| 欧美丰满少妇xxxbbb| 已婚少妇美妙人妻系列| 一区二区三区蜜桃| 女一区二区三区| 在线亚洲观看| 一道精品视频一区二区三区图片| 国产精选一区| 精品伦理一区二区| 欧美熟妇交换久久久久久分类| 日本美女爱爱视频| 国产三级欧美三级日产三级99| 欧美日本乱大交xxxxx| 国产亚洲一区在线| gogogo高清在线观看免费完整版| 日韩欧美国产精品综合嫩v| 一区二区欧美激情| 自拍视频国产精品| av片在线免费观看| 国产精品久久久久久99| 草草在线视频| 精品人伦一区二区三区蜜桃免费| 欧美猛男男男激情videos| 色棕色天天综合网| 亚洲一区在线观看免费| 制服丨自拍丨欧美丨动漫丨| 国产精品18久久久久久久网站| 亚洲视频资源在线| 国产日韩av网站| 亚洲免费不卡视频| 国产综合色香蕉精品| 成人h动漫在线| 成人国产精品久久久网站| 国产视频亚洲精品| 欧美在线精品一区二区三区| 91黄视频在线| 一区在线免费观看| 中文字幕 日本| 久久久久久在线观看| 欧美一级爱爱视频| 色偷偷亚洲第一综合| 亚洲欧洲精品一区二区三区| 北条麻妃av高潮尖叫在线观看| 黄色片在线免费| 男女性杂交内射妇女bbwxz| 亚洲毛片av在线| 91久久精品无码一区二区| 啪一啪鲁一鲁2019在线视频| 亚洲一区二区三区精品中文字幕| 国产精品va无码一区二区| 欧美激情在线视频二区| 先锋在线资源一区二区三区| 在线免费av网址| 亚洲专区一区二区三区| 欧美午夜视频网站| 丝袜美腿亚洲一区二区图片| 欧美成人片在线| 天涯成人国产亚洲精品一区av| 久久最新视频| 欧美视频一二三区| 岛国精品资源网站| 91大神xh98hx在线播放|