func NewTimer
func NewTimer(d Duration) *Timer
NewTimer创建一个Timer,它会在最少过去时间段d后到期,向其自身的C字段发送当时的时间。
Timer是一次性的时间触发事件
虽然往通道写入数据了,但是后面不会堵塞,因为是内部开辟协程写入,不取从通道时间不堵塞,取时间就会堵塞
对于NewTimer和After这两种创建方法,则是Timer在超时(timer expire)后,执行一个标准库中内置的函数:sendTime。sendTime将当前当前事件send到timer的时间Channel中,那么说这个动作不会阻塞到timerproc的执行么?答案肯定是不会的,其原因就在下面代码中:
//$GOROOT/src/time/sleep.go
func NewTimer(d Duration) *Timer {
c := make(chan Time, 1)
t := &Timer{
C: c,
... ...
}
... ...
return t
}
func sendTime(c interface{}, seq uintptr) {
// Non-blocking send of time on c.
// Used in NewTimer, it cannot block anyway (buffer).
// Used in NewTicker, dropping sends on the floor is
// the desired behavior when the reader gets behind,
// because the sends are periodic.
select {
case c.(chan Time) <- Now():
default:
}
}
我们看到NewTimer中创建了一个buffered channel,size = 1。正常情况下,当timer expire,t.C无论是否有goroutine在read,sendTime都可以non-block的将当前时间发送到C中;同时,我们看到sendTime还加了双保险:通过一个select判断c buffer是否已满,一旦满了,直接退出,依然不会block,这种情况在reuse active timer时可能会遇到。
package main
import (
"fmt"
"time"
)
func main() {
timer := time.NewTimer(time.Duration(5) * time.Second)
fmt.Println(time.Now())
//NewTimer不会堵塞当前的
for {
fmt.Println(<-timer.C)
timer.Reset(2 * time.Second)
}
//timer = time.NewTimer(time.Duration(2) * time.Second)
//select {
//case <-timer.C:
// fmt.Println("执行...")
}
//---------------------------------------------------------------
2018-12-28 14:50:57.4505215 +0800 CST m=+0.005985001
2018-12-28 14:51:02.4512457 +0800 CST m=+5.006724301
2018-12-28 14:51:04.4515802 +0800 CST m=+7.007064901
2018-12-28 14:51:06.4519336 +0800 CST m=+9.007424301
2018-12-28 14:51:08.4523644 +0800 CST m=+11.007861201
2018-12-28 14:51:10.452537 +0800 CST m=+13.008039801
第一次取数据的时候单次定时器是5S , 等对定时器复位后则 , 定时器复位并定时为2S
time.After()返回只读channel
package main
import (
"fmt"
"time"
)
func main() {
ch := make(chan string)
go func() {
time.Sleep(time.Second * 2)
ch <- "result"
}()
select {
case res := <-ch:
fmt.Println(res)
case <-time.After(time.Second * 1):
/*
func After(d Duration) <-chan Time {
return NewTimer(d).C
}
返回值为只读channel
*/
//只读channel,只写channel
fmt.Println("timeout")
}
}
/*
Go中channel可以是只读、只写、同时可读写的。
//定义只读的channel
read_only := make (<-chan int)
//定义只写的channel
write_only := make (chan<- int)
//可同时读写
read_write := make (chan int)*/