写点什么

Go 语言那些事儿之管道的关闭

用户头像
Regan Yue
关注
发布于: 1 小时前
Go语言那些事儿之管道的关闭

Go 语言那些事儿之管道的关闭

之前我们提到了怎么定义管道,讲了管道的读取和写入。那么今天我们就来讲一讲管道的关闭。


先来看一个简单的例子:


func main() {  ch := make(chan int,10)  for i := 0;i < 5;i++{    ch <- i*i  }  close(ch)
for x:= range ch { fmt.Println(x) }}
复制代码


先思考一下它会输出什么?


没错它的输出结果是:


014916
复制代码


这段的代码就是定义一个管道,然后遍历零到四,将零到四的平方塞入管道。我们知道这个管道定义时,被赋予了 10 的缓存能力,所以能够缓存 10 个单位的数据。而我们这里只需要存 5 个单位,你会想是不是还有 5 个单位是空闲的?是的。


下面我们再看一看多个协程并发读写管道:


func main()  {  ch := make(chan int,10)
go func() { for i:=0;i<5;i++{ ch <- i * i fmt.Println("写入",i*i) time.Sleep(1 * time.Second)
} // The close built-in function closes a channel, which must be either // bidirectional or send-only. It should be executed only by the sender, // never the receiver, and has the effect of shutting down the channel after // the last sent value is received. After the last value has been received // from a closed channel c, any receive from c will succeed without // blocking, returning the zero value for the channel element. The form // x, ok := <-c // will also set ok to false for a closed channel. close(ch) fmt.Println("管道已关闭,写入协程结束") }() go func() { for x:= range ch{ fmt.Println("读出",x) } fmt.Println("读取协程结束") }()
time.Sleep(6 * time.Second) fmt.Println("GAME OVER")}
复制代码


运行结果是:


写入 0读出 0读出 1写入 1写入 4读出 4写入 9读出 9写入 16读出 16读取协程结束管道已关闭,写入协程结束GAME OVER
复制代码


这段代码的作用是建立一个缓存能力为 10 的管道,建立两条协程。一条协程用来将零到四的平方写入管道,写完之后关闭管道。另一条协程是用来将管道内的数据读出。


由于两条协程是并发的,所以一条协程往管道里写入一条数据,马上另一条协程就往管道里读取一条数据。这里那条写入数据的协程关闭了管道,那么就会通知那边不需要再继续从管道中读取数据了,那么另外一条协程就不会往管道里面读取数据了。如果没有close(ch),也就是不关闭管道,那么另一条协程就会不断读取管道,直到主协程正常结束,那条子协程才会结束。


我们需要注意,内建函数 close 函数是用来关闭通道的,并且只有双向的和仅发送的管道才能被关闭。


还有一点需要注意的是,这个 close 函数需要由发送方执行,而不是由接收方执行。从一个关闭的通道接收完最后一个值后,从该管道接收的任何值都将成功,不会阻塞,并返回零值。但是对于x, ok := <-c,将会为关闭的管道的 ok 值赋予false值。

发布于: 1 小时前阅读数: 2
用户头像

Regan Yue

关注

还未添加个人签名 2020.08.12 加入

还未添加个人简介

评论

发布
暂无评论
Go语言那些事儿之管道的关闭