go里面select-case和time.Ticker的使用注意事项
2015-01-13 16:47
495 查看
上周末参加Go技术聚会,京东的美女工程师讲到一个select-case和time.Ticker的使用注意事项(真实的应用场景是:在测试收包的顺序的时候,加了个tick就发现丢包了),觉得很有意思,记录一下。
输出如下:
问题出在这个select里面:
select {
case ch <- i:
case <-tick.C:
fmt.Printf("%d: case <-tick.C\n", i)
}
当两个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:
}
两种解决方案的输出都是希望的结果:
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)
}
当两个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里面select-case和time.Ticker的使用注意事项
- ACE_Time_Value使用注意事项
- 使用select * from (select * a inner join b on....)注意事项
- mybatis selectMap方法使用注意事项
- java中使用switch-case的用法及注意事项超全总结
- linux下使用gettimeofday获取当前时间的注意事项
- linux里面$?的使用注意事项
- [小结]select的使用注意事项
- PCL 使用 pcl::visualization::PCLVisualizer 类里面的键盘事件方法 如何使用及需要注意的事项
- JS实现select去除option的使用注意事项
- SELECT LAST_INSERT_ID() 的使用和注意事项
- java中使用switch-case的用法及注意事项超全总结
- mybatis select语句缓存使用注意事项
- 【Java基础】6、java中使用switch-case的用法及注意事项超全总结
- 使用Select的3个注意事项
- ACE_Time_Value使用注意事项(续)
- C语言-Switch 和case 的使用注意事项以及穿透效果的使用
- MySQL(17):Select-union(联合查询)使用注意事项
- SELECT LAST_INSERT_ID() 的使用和注意事项
- 【Java面试题】1 Java中使用switch-case的用法及注意事项超全总结