gtimer_loop.go 2.1 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788
  1. // Copyright GoFrame Author(https://github.com/gogf/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/gogf/gf.
  6. package gtimer
  7. import (
  8. "time"
  9. "github.com/gogf/gf/container/glist"
  10. )
  11. // start starts the ticker using a standalone goroutine.
  12. func (w *wheel) start() {
  13. go func() {
  14. ticker := time.NewTicker(time.Duration(w.intervalMs) * time.Millisecond)
  15. for {
  16. select {
  17. case <-ticker.C:
  18. switch w.timer.status.Val() {
  19. case StatusRunning:
  20. w.proceed()
  21. case StatusStopped:
  22. // Do nothing.
  23. case StatusClosed:
  24. ticker.Stop()
  25. return
  26. }
  27. }
  28. }
  29. }()
  30. }
  31. // proceed checks and rolls on the job.
  32. // If a timing job is time for running, it runs in an asynchronous goroutine,
  33. // or else it removes from current slot and re-installs the job to another wheel and slot
  34. // according to its leftover interval in milliseconds.
  35. func (w *wheel) proceed() {
  36. n := w.ticks.Add(1)
  37. l := w.slots[int(n%w.number)]
  38. length := l.Len()
  39. if length > 0 {
  40. go func(l *glist.List, nowTicks int64) {
  41. entry := (*Entry)(nil)
  42. nowMs := time.Now().UnixNano() / 1e6
  43. for i := length; i > 0; i-- {
  44. if v := l.PopFront(); v == nil {
  45. break
  46. } else {
  47. entry = v.(*Entry)
  48. }
  49. // Checks whether the time for running.
  50. runnable, addable := entry.check(nowTicks, nowMs)
  51. if runnable {
  52. // Just run it in another goroutine.
  53. go func(entry *Entry) {
  54. defer func() {
  55. if err := recover(); err != nil {
  56. if err != panicExit {
  57. panic(err)
  58. } else {
  59. entry.Close()
  60. }
  61. }
  62. if entry.Status() == StatusRunning {
  63. entry.SetStatus(StatusReady)
  64. }
  65. }()
  66. entry.job()
  67. }(entry)
  68. }
  69. // If rolls on the job.
  70. if addable {
  71. //If StatusReset , reset to runnable state.
  72. if entry.Status() == StatusReset {
  73. entry.SetStatus(StatusReady)
  74. }
  75. entry.wheel.timer.doAddEntryByParent(entry.rawIntervalMs, entry)
  76. }
  77. }
  78. }(l, n)
  79. }
  80. }