Go语言channel超时处理

Go语言channel超时处理教程

并发编程 的通信过程中,经常会遇到超时问题,即向 channel 写数据时发现 channel 已满,或者从 channel 试图读取数据时发现 channel 为空。如果不正确处理这些情况,很可能会导致整个 goroutine 锁死。

Go语言channel超时场景

语法

name := <-chanName

说明

我们从管道 chanName 里面接受数据,并将接受到的数据存放到 变量 name 中,如果我们的程序一直没有给管道 chanName 发送数据,那么上面的代码就会永久的阻塞。

那么,此时,如果没有合理的超时处理机制,这行代码很可能会导致整个进程阻塞。

Go语言channel超时处理

Go 语言 并没有为 channel 超时提供直接的解决方案,但我们可以利用 select 机制。虽然 select 机制不是专为超时而设计的,却能很方便地解决超时问题。

select 的特点是只要其中一个 case 已经完成,程序就会继续往下执行,而不会考虑其他 case 的情况。

案例

channel超时处理

使用 select 实现 channel 超时处理

package main import ( "fmt" "time" ) func main() { fmt.Println("嗨客网(www.haicoder.net)") ch := make(chan int) quit := make(chan bool) //新开一个协程 go func() { for { select { case num := <-ch: //如果有数据,下面打印。但是有可能ch一直没数据 fmt.Println("received num = ", num) case <-time.After(3 * time.Second): //上面的ch如果一直没数据会阻塞,那么select也会检测其他case条件,检测到后3秒超时 fmt.Println("TimeOut") quit <- true //写入 } } }() //别忘了() for i := 0; i < 3; i++ { ch <- i time.Sleep(time.Second) } <-quit //这里暂时阻塞,直到可读 fmt.Println("Over") }

程序运行后,控制台输出如下:

27_golang channel超时处理.png

首先,我们使用 make 创建了一个 无缓冲 的管道 ch 和 quit,接着, 使用 go 创建了一个协程。

在协程里,我们使用 for 循环 加上 select 语句,同时监听管道 ch 和 time 定时器,如果 3 秒钟管道 ch 没有接收到数据,那么此时会走到 time 分支,此时我们使用 quit 管道发送一条消息。

main 协程接收到 quit 消息,自动退出,通过 select 我们实现了管道的超时控制。

Go语言channel超时处理总结

在并发编程的通信过程中,经常会遇到超时问题,即向 channel 写数据时发现 channel 已满,或者从 channel 试图读取数据时发现 channel 为空。如果不正确处理这些情况,很可能会导致整个 goroutine 锁死。Go 语言 channel 超时场景:

name := <-chanName

我们从管道 chanName 里面接受数据,并将接受到的数据存放到变量 name 中,如果我们的程序一直没有给管道 chanName 发送数据,那么上面的代码就会永久的阻塞。

那么,此时,如果没有合理的超时处理机制,这行代码很可能会导致整个进程阻塞。