断续器会在时间到期后立即进入下一个周期并等待再次到达,直到停止。断续器传达到通知的默认途径是它的字段C,是一个channel,容量为1
先看代码
package main
import (
"fmt"
"time"
)
func main() {
intchan := make(chan int, 1)
ticker := time.NewTicker(time.Second)
go func() {
for _ = range ticker.C {
select {
case intchan <- 1:
case intchan <- 2:
case intchan <- 3:
}
}
fmt.Println("end sender")
}()
var sum int
for e := range intchan {
fmt.Printf("receive: %d\n", e)
sum += e
if sum > 10 {
fmt.Printf("get :%d\n", sum)
ticker.Stop()
break
}
}
//fmt.Println("last receive %d", <-intchan)
//ticker.Stop()
fmt.Println("end receive")
}
上述程序中,发送方用断续器ticker每隔1s向intchan通道发送一个[1,3]随机数,这个操作不会主动停止,接收方一直接收直到接收到的数的和大于10为止,但是并不会打印“end sender”这个字符串
原因分析:
如果没有:
fmt.Println("last receive %d", <-intchan)
ticker.Stop()
则发送方仍然会发送一次随机数,随后接收方不会再从通道读取值,下一次循环的时候,就会堵塞再select中
但是如果time.stop()后.仍然不会打印“end sender”
原因分析:
查阅资料可知:
ticker.stop()后
// Stop turns off a ticker. After Stop, no more ticks will be sent.
// Stop does not close the channel, to prevent a read from the channel succeeding
// incorrectly.
翻译一下就是:就是Stop会停止Ticker,停止后,Ticker不会再被发送,但是Stop不会关闭通道,防止读取通道发生错误。所以ticker.stop后,for _ = range ticker.C此处已经不会有任何值了,所以仍然堵塞。
那么如何正确停止Ticker呢:
package main
import (
"fmt"
"time"
)
func main() {
intchan := make(chan int, 1)
ch := UserTicker(intchan)
var sum int
for e := range intchan {
fmt.Printf("receive: %d\n", e)
sum += e
if sum > 10 {
fmt.Printf("get :%d\n", sum)
break
}
}
ch <- true
time.Sleep(2 * time.Second)
fmt.Println("end receive")
close(ch)
}
func UserTicker(intchan1 chan int) chan bool {
stopchan := make(chan bool)
ticker := time.NewTicker(time.Second)
go func() {
defer ticker.Stop()
for {
select {
case <-ticker.C:
setValue(intchan1)
fmt.Println("ticker")
case <-stopchan:
fmt.Println("end sender")
return
}
}
}()
return stopchan
}
func setValue(intchan1 chan int) {
select {
case intchan1 <- 1:
fmt.Println("send 1")
case intchan1 <- 2:
fmt.Println("send 2")
case intchan1 <- 3:
fmt.Println("send 3")
}
}