简析go语言channel与select结合使用的惯用法
go语言中channel和select结合使用可以实现多种功能。
1. 利用default分支避免阻塞
for { select { case x := <-c: fmt.Println(x) default: ... } }
2.实现超时机制
// 使用time.After实现超时机制 select { case x := <-c: fmt.Println(x) case time.After(10 * time.Second): // channel c阻塞10s后将执行该分支 ... } // 使用time.Timer实现超时机制 timer := time.NewTimer(10 * time.Second) defer timer.Stop() select { case x := <-c: fmt.Println(x) case <-timer.C: // channel c阻塞10s后将执行该分支 ... }
3. 实现心跳机制
heartbeat := time.NewTimer(10 * time.Second) defer heartbeat.Stop() for { select { case x := <-c: fmt.Println(x) case <-heartbeat.C: // 处理心跳逻辑 ... } }
注:time.After, time.Timer, time.Ticker的区别及注意事项
- time.Ticker和time.Timer都属于定时器
- time.Ticker和time.Timer在使用之后都必须注意要关闭(stop),避免资源浪费
- time.Timer到固定时间后仅会执行一次,可以通过Reset方法来实现每隔固定时间执行
func main() { timer := time.NewTimer(1 * time.Second) defer timer.Stop() go func(t *time.Timer) { // 仅执行一次该go routine就会退出 <-t.C fmt.Println("do work...") }(timer) select {} } // 多次执行版本 func main() { timer := time.NewTimer(1 * time.Second) defer timer.Stop() go func(t *time.Timer) { for { <-t.C fmt.Println("do work...") t.Reset(1 * time.Second) // 使用Rest方法重置定时器,实现多次执行。reset重新开始计时,如果调用时t还在等待中会返回true;如果t已经到期或者被停止了会返回false } }(timer) select {} }
4.time.Ticker每隔固定时间都会触发,多次执行
func main() { timer := time.NewTicker(1 * time.Second) defer timer.Stop() go func(t *time.Ticker) { // 该goroutine会多次执行 for { <-t.C fmt.Println("do work...") } }(timer) select {} } $ go run ticker-case.go do work... do work... do work... ... do work...
5.time.After相当于time.Timer().C,最常用于和select channel结合使用实现超时机制
Go语言基础及实战 文章被收录于专栏
Go语言学习笔记、语法知识、技术要点和个人理解及实战