定时器
1.定时器结构函数
type Timer struct {
C <-chan Time // 接受定时器事件的通道
r runtimeTimer
}
type runtimeTimer struct {
tb uintptr
i int
when int64
period int64
f func(interface{}, uintptr) // NOTE: must not be closure
arg interface{}
seq uintptr
}
2.建立定时器ui
func NewTimer(d Duration) *Timer
var timer = NewTimer(time.Second)
go func() {
for {
select {
case <-timer.C:
fmt.Println("time out.")
}
}
}()func NewTimer(d Duration) *Timer {
c := make(chan Time, 1) // 建立一个带有一个Time结构缓冲的通道
t := &Timer{
C: c,
r: runtimeTimer{ // 运行时定时器
when: when(d), // 定时多久
f: sendTime, // Golang写入时间的回调接口
arg: c, // 往哪一个通道写入时间
},
}
startTimer(&t.r) // 启动提交定时器
return t
}
// 时间到后,Golang自动调用sendTime接口,尝试往c通道写入时间
func sendTime(c interface{}, seq uintptr) {
// 给c通道以非阻塞方式发送时间
// 若是被用于NewTimer, 不管如何不能阻塞.
// 若是被用于NewTicker,接收方未及时接受时间,则会丢弃掉,由于发送时间是周期性的。
select {
case c.(chan Time) <- Now():
default:
}
}
func startTimer(*runtimeTimer)package main
import (
"fmt"
"time"
)
func main() {
// 建立延迟3s的定时器
exit := make(chan bool)
timer := time.NewTimer(3 * time.Second)
go func() {
defer func() {
exit <- true
}()
select {
case <-timer.C:
fmt.Println("time out.")
return
}
}()
<-exit
}
3.中止定时器blog
func (t *Timer) Stop() bool
if !t.Stop() {
<-t.C
}func stopTimer(*runtimeTimer) bool
package main
import (
"fmt"
"time"
)
func main() {
timer := time.NewTimer(time.Second)
time.Sleep(time.Millisecond * 500)
timer.Stop()
fmt.Println("timer stopped")
time.Sleep(time.Second * 3)
}
4.重置定时器
func (t *Timer) Reset(d Duration) bool
package main
import (
"fmt"
"time"
)
func doTimer(t *time.Timer, exit chan<- bool) {
go func(t *time.Timer) {
defer func() {
exit <- true
}()
for {
select {
case c := <-t.C:
fmt.Println("timer timeout at", c)
return
}defer func() {
ticker.Stop()
fmt.Println("ticker stopped")
} ()
}
}(t)
}
func main() {
sign := make(chan bool)
timer := time.NewTimer(time.Second * 3)
doTimer(timer, sign)
time.Sleep(time.Second)
// 实际测试:注释下面三行代码,效果同样。
if !timer.Stop() {
<-timer.C
}
timer.Reset(time.Second * 3)
fmt.Println("timer reset at", time.Now())
<-sign
}
5.After接口
func After(d Duration) <-chan Time
package main
import (
"fmt"
"time"
)
func main() {
sign := make(chan bool)
chan1 := make(chan int)
chan2 := make(chan int)
defer func() {
close(sign)
close(chan1)
close(chan2)
}()
go func() {
for {
select {
case c := <-time.After(time.Second * 3):
fmt.Println("After at", c)
// 若不往sign通道写入数据,程序循环每隔3s执行当前case分支。
sign <- true
case c1 := <-chan1:
fmt.Println("c1", c1)
case c2 := <-chan2:
fmt.Println("c1", c2)
}
}
}()
<-sign
}
6.AfterFun接口
func AfterFunc(d Duration, f func()) *Timer
package main
import (
"fmt"
"time"
)
func main() {
timer := time.AfterFunc(time.Second*3, func() {
fmt.Println("AfterFunc Callback")
})
time.Sleep(time.Second * 5)
timer.Stop()
}
断续器
type Ticker struct {
C <-chan Time // The channel on which the ticks are delivered.
r runtimeTimer
}
type runtimeTimer struct {
tb uintptr
i int
when int64
period int64
f func(interface{}, uintptr) // NOTE: must not be closure
arg interface{}
seq uintptr
}var ticker = time.NewTicker(time.Second)
var ticker = time.NewTicker(time.Second) ticker.Stop()
实例一:使用Ticker(并使用时间控制ticker)
package main
import (
"fmt"
"time"
)
func TickerTest() *time.Ticker {
// 建立一个断续器
var ticker = time.NewTicker(time.Second)
go func() {
// 使用for + range组合处理断续器
for t := range ticker.C {
fmt.Println("tick at", t)
}
}()
return ticker
}
func main() {
ticker := TickerTest()
time.Sleep(time.Second * 10)
ticker.Stop()
}
实例二:使用channel控制ticker
package main
import (
"fmt"
"time"
)
func DoTicker(ticker *time.Ticker) chan<- bool {
stopChan := make(chan bool)
go func(ticker *time.Ticker) {
// 注册中止ticker方法
defer ticker.Stop()
for {
select {
// 处理断续器事件
case t := <-ticker.C:
fmt.Println("tick at", t)
// 接受外部中止断续器事件
case stop := <-stopChan:
if stop {
fmt.Println("DoTicker Exit")
return
}
}
}
}(ticker)
// 返回由外部控制Ticker中止的Channel
return stopChan
}
func main() {
var ticker = time.NewTicker(time.Second)
stopChan := DoTicker(ticker)
time.Sleep(time.Second * 10)
// 中止断续器
stopChan <- true
time.Sleep(time.Second)
close(stopChan)
}
实例三:使用channel控制中止ticker
package main
import (
"fmt"
"time"
)
func DoTicker(ticker *time.Ticker, times int) {
// 建立有times个缓冲的byte通道
stopChan := make(chan byte, times)
go func(ticker *time.Ticker) {
defer func() {
// 通过调试,defer语句块并未执行
ticker.Stop()
fmt.Println("ticker stopped")
} ()
for t := range ticker.C {
fmt.Println("write stop channel")
// 写满times次后,当前goroutine自动退出
stopChan <- 0
fmt.Println("tick at", t)
}
// 经调试,该语句并未执行
fmt.Println("DoTicker1 Exit")
}(ticker)
}
func main() {
var ticker = time.NewTicker(time.Second)
DoTicker(ticker, 5)
time.Sleep(time.Second * 10)
}write stop channel tick at 2019-03-13 11:44:35.932692894 +0800 CST m=+1.000442776 write stop channel tick at 2019-03-13 11:44:36.932643384 +0800 CST m=+2.000393270 write stop channel tick at 2019-03-13 11:44:37.932565147 +0800 CST m=+3.000315031 write stop channel tick at 2019-03-13 11:44:38.932735589 +0800 CST m=+4.000485469 write stop channel tick at 2019-03-13 11:44:39.932553565 +0800 CST m=+5.000303443 write stop channel Process finished with exit code 0