Golang Select & 定时器
1. Select
select: 管理多个channel,监听channel上的数据流动。类似switch语法,但每个case语句必须是IO操作。多个case同时满足,任选一个执行。
- 处理一个或多个channel的发送和接收
- 同时有多个channel时,随机处理
- 可用空select来阻塞main函数
- 可设置超时
default语句:
- 有default:select语句不会被阻塞,执行default后,程序的执行会从select语句中恢复,进入下一次轮询。比较消耗资源。
- 没有default:select语句将被阻塞,直到至少有一个通信可以进行下去
1.1 管理多个通道
func main() {
ch := make(chan int)
done := make(chan bool)
// 消费者
go func() {
for i := 0; i < 10; i++ {
fmt.Printf("%d ", <-ch)
}
fmt.Println()
done <- true
}()
fib(ch, quit)
}
func fib(ch chan<- int, quit <-chan bool) {
x, y := 1, 1
for {
select {
case ch <- x:
x, y = y, x+y
case <-done:
fmt.Println("Done.")
return // break只能跳出select,无法跳出for循环
}
}
}
1.2 作为发送者
func main() {
c := make(chan int)
go func() {
for v := range c {
fmt.Println(v)
}
}()
for i := 0; i < 100; i++ {
select {
case c <- 0:
case c <- 1:
}
}
}
1.3 超时处理
case <-time.After(5 * time.Second)
: 其他channel阻塞时间超过5s时执行
func main() {
ch := make(chan int)
done := make(chan bool)
go func() {
for {
select {
case x := <-ch:
fmt.Printf("%d ", x)
case <-time.After(5 * time.Second):
fmt.Println("\nTimeout")
done <- true
return
}
}
}()
for i := 0; i < 10; i++ {
ch <- i
time.Sleep(time.Second)
}
<-done
}
1.4 避免造成死锁
select 在执行过程中,必须命中其中的某一分支, 否则deadlock
func main() {
c1 := make(chan string, 1)
c2 := make(chan string, 1)
c1 <- "ok"
c2 <- "good"
select {
case msg := <-c1:
fmt.Printf("c1 receive %s\n", msg)
case msg := <-c2:
fmt.Printf("c2 receive %s\n", msg)
default:
fmt.Println("no data")
}
}
2. 定时器
2.1 一次性定时任务
time.NewTimer(d Duration) *Timer
<-timer.C
: 阻塞等待,返回定时器时间timer.Stop()
:timer.Reset(d Duration)
:
func main() {
timer := time.NewTimer(2 * time.Second)
go func() {
<-timer.C
fmt.Println("Goroutine is done.")
}()
timer.Stop()
// 重置定时器,上面的 goroutine 将继续执行
timer.Reset(5 * time.Second)
select {
case <-time.After(10 * time.Second):
}
}
2.2 周期性定时任务
time.NewTicker(d Duration) *Ticker
<-ticker.C
: 阻塞等待,返回定时器时间ticker.Stop()
:
func main() {
ticker := time.NewTicker(2 * time.Second)
count := 0
for {
<-ticker.C
count++
fmt.Printf("%d ", count)
if count == 10 {
ticker.Stop()
break
}
}
fmt.Println()
}
2.3 延迟操作总结
time.Sleep(time.Second * 2)
<- time.After(time.Second * 2)
timer := time.NewTimer(time.Second * 2)
<-timer.C