周期定時器
func main() {
timer := time.NewTicker(1 * time.Second) //NewTicker是周期定時器,NewTimer是普通定時器只能用一次
for {
<-timer.C
fmt.Println("good")
}
}
定時器
time.Sleep(time.Second)
//2Timer.C
myTimer := time.NewTimer(time.Second * 2) //創建定時器,指定定時時長
nowTime := <-myTimer.C //定時滿,系統自動寫入時間
fmt.Println("現在時間", nowTime)
//3 time.After
nowTime = <-time.After(time.Second * 2)
fmt.Println("現下時間", nowTime)
//定時器的停止和重置
myTimer2 := time.NewTimer(time.Second * 3)
go func() {
<-myTimer2.C
fmt.Println("子go程,定時完畢")
}()
myTimer2.Stop() //停止
myTimer.Reset(1 * time.Second) //重置
下面的寫法會造成內存泄漏
package main
import (
"time"
)
func main() {
ch := make(chan int, 10)
go func() {
var i= 1
for {
i++
ch <- i
}
}()
for {
select {
case x := <-ch:
println(x)
case <-time.After(3 * time.Minute):
println(time.Now().Unix())
}
}
}
`在for循環每次select的時候,都會實例化一個一個新的定時器。該定時器在3分鍾后,才會被激活,但是激活后已經跟select無引用關系,被gc給清理掉。
換句話說,被遺棄的time.After定時任務還是在時間堆里面,定時任務未到期之前,是不會被gc清理的。
也就是說每次循環實例化的新定時器對象需要3分鍾才會可能被GC清理掉,如果我們把上面復現代碼中的3分鍾改小點,改成10秒鍾,通過top命令會發現大概10秒鍾后,該程序占用的內存增長到1.05G后基本上就不增長了`
下面的代碼是解決方案
package main
import (
"time"
)
func main() {
ch := make(chan int, 10)
go func() {
for {
ch <- 100
}
}()
idleDuration := 3 * time.Minute
idleDelay := time.NewTimer(idleDuration) //綜上,在go代碼中,在for循環里不要使用select + time.After的組合,可以使用time.NewTimer替代
defer idleDelay.Stop() //記得要關閉定時器
for {
idleDelay.Reset(idleDuration)
select {
case x := <- ch:
println(x)
case <-idleDelay.C:
return
}
}
}