分享
golang 中的 time 包的 Ticker
liang1101 · · 7139 次点击 · · 开始浏览这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。
真实的应用场景是:在测试收包的顺序的时候,加了个 tick 就发现丢包了
那么来看一个应用例子:
package main import ( "fmt" "runtime" "time" ) func init() { runtime.GOMAXPROCS(runtime.NumCPU()) } func main() { ch := make(chan int, 1024) go func(ch chan int) { for { val := <-ch fmt.Printf("val:%d\n", val) } }(ch) tick := time.NewTicker(1 * time.Second) for i := 0; i < 20; i++ { select { case ch <- i: case <-tick.C: fmt.Printf("%d: case <-tick.C\n", i) } time.Sleep(200 * time.Millisecond) } close(ch) tick.Stop() }
输出结果如下:
val:0 val:1 val:2 val:3 val:4 val:5 6: case <-tick.C val:7 val:8 val:9 10: case <-tick.C val:11 val:12 val:13 val:14 15: case <-tick.C val:16 val:17 val:18 val:19
问题出在这个select里面:
select { case ch <- i: case <-tick.C: fmt.Printf("%d: case <-tick.C\n", i) }
[tick.C 介绍说明] 当两个 case 条件都满足的时候,运行时系统会通过一个伪随机的算法决定哪个case将会被执行。所以当 tick.C 条件满足的那个循环,有某种概率造成 ch<-i 没有发送(虽然通道两端没有阻塞,满足发送条件)
解决方案1:一旦 tick.C 随机的 case 被随机到,就多执行一次 ch<-i (不体面,如果有多个case就不通用了)
select { case ch <- i: case <-tick.C: fmt.Printf("%d: case <-tick.C\n", i) ch <- i }
解决方案2:将tick.C的case单独放到一个select里面,并加入一个default(保证不阻塞)
select { case ch <- i: } select { case <-tick.C: fmt.Printf("%d: case <-tick.C\n", i) default: }
两种解决方案的输出都是希望的结果:
val:0 val:1 val:2 val:3 val:4 5: case <-tick.C val:5 val:6 val:7 val:8 val:9 10: case <-tick.C val:10 val:11 val:12 val:13 val:14 15: case <-tick.C val:15 val:16 val:17 val:18 val:19
有疑问加站长微信联系(非本文作者)
入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889
关注微信7139 次点击
上一篇:cache2go学习
添加一条新回复
(您需要 后才能回复 没有账号 ?)
- 请尽量让自己的回复能够对别人有帮助
- 支持 Markdown 格式, **粗体**、~~删除线~~、
`单行代码` - 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
- 图片支持拖拽、截图粘贴等方式上传
收入到我管理的专栏 新建专栏
真实的应用场景是:在测试收包的顺序的时候,加了个 tick 就发现丢包了
那么来看一个应用例子:
package main import ( "fmt" "runtime" "time" ) func init() { runtime.GOMAXPROCS(runtime.NumCPU()) } func main() { ch := make(chan int, 1024) go func(ch chan int) { for { val := <-ch fmt.Printf("val:%d\n", val) } }(ch) tick := time.NewTicker(1 * time.Second) for i := 0; i < 20; i++ { select { case ch <- i: case <-tick.C: fmt.Printf("%d: case <-tick.C\n", i) } time.Sleep(200 * time.Millisecond) } close(ch) tick.Stop() }
输出结果如下:
val:0 val:1 val:2 val:3 val:4 val:5 6: case <-tick.C val:7 val:8 val:9 10: case <-tick.C val:11 val:12 val:13 val:14 15: case <-tick.C val:16 val:17 val:18 val:19
问题出在这个select里面:
select { case ch <- i: case <-tick.C: fmt.Printf("%d: case <-tick.C\n", i) }
[tick.C 介绍说明] 当两个 case 条件都满足的时候,运行时系统会通过一个伪随机的算法决定哪个case将会被执行。所以当 tick.C 条件满足的那个循环,有某种概率造成 ch<-i 没有发送(虽然通道两端没有阻塞,满足发送条件)
解决方案1:一旦 tick.C 随机的 case 被随机到,就多执行一次 ch<-i (不体面,如果有多个case就不通用了)
select { case ch <- i: case <-tick.C: fmt.Printf("%d: case <-tick.C\n", i) ch <- i }
解决方案2:将tick.C的case单独放到一个select里面,并加入一个default(保证不阻塞)
select { case ch <- i: } select { case <-tick.C: fmt.Printf("%d: case <-tick.C\n", i) default: }
两种解决方案的输出都是希望的结果:
val:0 val:1 val:2 val:3 val:4 5: case <-tick.C val:5 val:6 val:7 val:8 val:9 10: case <-tick.C val:10 val:11 val:12 val:13 val:14 15: case <-tick.C val:15 val:16 val:17 val:18 val:19