├── README.md └── timer.go /README.md: -------------------------------------------------------------------------------- 1 | # timer 2 | Go语言各种定时器的实现。 3 | -------------------------------------------------------------------------------- /timer.go: -------------------------------------------------------------------------------- 1 | package timer 2 | 3 | import ( 4 | "log" 5 | "sync" 6 | "time" 7 | ) 8 | 9 | type Timer struct { 10 | setting map[string]*Clock 11 | closed bool 12 | sync.RWMutex 13 | } 14 | 15 | func NewTimer() *Timer { 16 | return &Timer{ 17 | setting: make(map[string]*Clock), 18 | } 19 | } 20 | 21 | // 休眠等待,并返回定时器是否可以继续使用 22 | func (self *Timer) Sleep(id string) bool { 23 | self.RLock() 24 | if self.closed { 25 | self.RUnlock() 26 | return false 27 | } 28 | 29 | c, ok := self.setting[id] 30 | self.RUnlock() 31 | if !ok { 32 | return false 33 | } 34 | 35 | c.sleep() 36 | 37 | self.RLock() 38 | if self.closed { 39 | return false 40 | } 41 | _, ok = self.setting[id] 42 | self.RUnlock() 43 | 44 | return ok 45 | } 46 | 47 | // @bell==nil时为倒计时器,此时@tol为睡眠时长 48 | // @bell!=nil时为闹铃,此时@tol用于指定醒来时刻(从now起遇到的第tol个bell) 49 | func (self *Timer) Set(id string, tol time.Duration, bell *Bell) bool { 50 | self.Lock() 51 | defer self.Unlock() 52 | if self.closed { 53 | log.Printf("************************ ……设置定时器 <%s> 失败,定时系统已关闭 ……************************", id) 54 | return false 55 | } 56 | c, ok := newClock(id, tol, bell) 57 | if !ok { 58 | log.Printf("************************ ……设置定时器 <%s> 失败,参数不正确 ……************************", id) 59 | return ok 60 | } 61 | self.setting[id] = c 62 | log.Printf("************************ ……设置定时器 <%s> 成功 ……************************", id) 63 | return ok 64 | } 65 | 66 | func (self *Timer) Drop() { 67 | self.Lock() 68 | defer self.Unlock() 69 | self.closed = true 70 | for _, c := range self.setting { 71 | c.wake() 72 | } 73 | self.setting = make(map[string]*Clock) 74 | } 75 | 76 | type ( 77 | Clock struct { 78 | id string 79 | // 模式(闹铃or倒计时) 80 | typ int 81 | // 倒计时的睡眠时长 82 | // 或指定闹铃醒来时刻为从now起遇到的第tol个bell 83 | tol time.Duration 84 | // 闹铃醒来时刻 85 | bell *Bell 86 | timer *time.Timer 87 | } 88 | Bell struct { 89 | Hour int 90 | Min int 91 | Sec int 92 | } 93 | ) 94 | 95 | const ( 96 | // 闹钟 97 | A = iota 98 | // 倒计时 99 | T 100 | ) 101 | 102 | // @bell==nil时为倒计时器,此时@tol为睡眠时长 103 | // @bell!=nil时为闹铃,此时@tol用于指定醒来时刻(从now起遇到的第tol个bell) 104 | func newClock(id string, tol time.Duration, bell *Bell) (*Clock, bool) { 105 | if tol <= 0 { 106 | return nil, false 107 | } 108 | if bell == nil { 109 | return &Clock{ 110 | id: id, 111 | typ: T, 112 | tol: tol, 113 | timer: newT(), 114 | }, true 115 | } 116 | if !(bell.Hour >= 0 && bell.Hour < 24 && bell.Min >= 0 && bell.Min < 60 && bell.Sec >= 0 && bell.Sec < 60) { 117 | return nil, false 118 | } 119 | return &Clock{ 120 | id: id, 121 | typ: A, 122 | tol: tol, 123 | bell: bell, 124 | timer: newT(), 125 | }, true 126 | } 127 | 128 | func (self *Clock) sleep() { 129 | d := self.duration() 130 | self.timer.Reset(d) 131 | t0 := time.Now() 132 | log.Printf("************************ ……定时器 <%s> 睡眠 %v ,计划 %v 醒来 ……************************", self.id, d, t0.Add(d).Format("2006-01-02 15:04:05")) 133 | <-self.timer.C 134 | t1 := time.Now() 135 | log.Printf("************************ ……定时器 <%s> 在 %v 醒来,实际睡眠 %v ……************************", self.id, t1.Format("2006-01-02 15:04:05"), t1.Sub(t0)) 136 | } 137 | 138 | func (self *Clock) wake() { 139 | self.timer.Reset(0) 140 | } 141 | 142 | func (self *Clock) duration() time.Duration { 143 | switch self.typ { 144 | case A: 145 | t := time.Now() 146 | year, month, day := t.Date() 147 | bell := time.Date(year, month, day, self.bell.Hour, self.bell.Min, self.bell.Sec, 0, time.Local) 148 | if bell.Before(t) { 149 | bell = bell.Add(time.Hour * 24 * self.tol) 150 | } else { 151 | bell = bell.Add(time.Hour * 24 * (self.tol - 1)) 152 | } 153 | return bell.Sub(t) 154 | case T: 155 | return self.tol 156 | } 157 | return 0 158 | } 159 | 160 | func newT() *time.Timer { 161 | t := time.NewTimer(0) 162 | <-t.C 163 | return t 164 | } 165 | --------------------------------------------------------------------------------