写点什么

管道 (Channel) 的读取与写入「让我们一起 Golang」

用户头像
Regan Yue
关注
发布于: 2 小时前
管道(Channel)的读取与写入「让我们一起Golang」

管道(Channel)的读取与写入「让我们一起 Golang」

我们都知道,协程是通过管道来进行通信、调度的。所以接下来我们引入管道的概念,通过管道可以来传递数据,协程与协程之间也可以通过管道来进行调度。


先来看一看第一段代码:


func main() {  //创建一个管道  ch := make(chan int)  //子协程读数据  go func() {    x := <-ch    fmt.Println("从管道内读数据:",x)  }()  //因为ch是int整形管道,往管道ch内只可写入整形数据,例如123。  //主协程写数据  ch <- 123  time.Sleep(time.Second)  fmt.Println("GAMEOVER")}
复制代码


这里是创建一个管道,然后用主协程往管道内写数据,然后从子协程往管道内读数据。


创建管道是用 make,第一部分是chan,第二个部分是管道内数据的数据类型。因为没有给管道制定长度,所以默认为 0。所以不能用于缓存。


该段程序是主协程往管道内写入 123,然后子协程从管道内读出 123.


运行结果是:


从管道内读数据: 123GAMEOVER
复制代码


那么思考一下,如果此段代码中将time.Sleep(time.Second)注释掉,也就是不使用这句代码不让主协程睡一秒,会出现什么情况?


是的,如果主协程不睡一秒的话,子协程可能还没读到数据,主协程就结束了,注意,主协程不是被杀死了,是正常结束了。


如果不睡一秒,而是使用runtime.Goexit()杀掉主协程,那么子协程就会失去约束,仍然会输出管道的数据。


如果主协程不写的话,我们从管道中读不到数据这样可以理解,但是你可能想不到的是,如果子协程不读的话,主协程也不能将数据成功写入管道中。


fatal error: all goroutines are asleep - deadlock!
goroutine 1 [chan send]:main.main()
复制代码


它会报一个致命错误,它预判会产生死锁。


这说明管道不能存东西,它是没有缓存能力的,只能用于传输数据。


下面来讲一讲管道关闭之后的读写。


  //定义管道  var ch chan int  //make才能初始化  ch  := make(chan int)  //关闭管道  close(ch)
复制代码


如果只定义管道,那么管道ch为 nil,此时不能关闭管道,此时关闭管道会报错。


只有将管道ch初始化之后,才能正常关闭管道。


不能重复关闭管道。


关闭会报错:


panic: close of closed channel
复制代码


我们再来看一看关闭管道后再来读会怎么样咯~


func main()  {  //定义管道  var ch chan int  //初始化管道,缓存能力为3  ch  = make(chan int , 3)  ch <- 123  //关闭管道  close(ch)  go func() {    x := <-ch    fmt.Println("读到",x)
//x,ok := <-ch //fmt.Println("读到",x,ok) }()
time.Sleep(time.Second) fmt.Println("GAME OVER")}
复制代码


此段代码主协程中先关闭管道,然后再开辟子协程来读取管道中的数据。能不能读到呢?


先看一看结果:


读到 123GAME OVER
复制代码


读到了!


因为我们给管道的第二个参数设置为 3,这就让管道有了缓存能力。而关闭管道之前已经将数据 123 存入了管道,之后再读取管道内数据是能够读取到的。


可以如果我们读取之后,再读一遍呢?会怎么样呢?


我们激活下面这段代码


x,ok := <-chfmt.Println("读到",x,ok)
复制代码


得到的运行结果是:


读到 123读到 0 falseGAME OVER
复制代码


则说明读取管道内的数据之后继续再读一遍是读到的默认数据 0,无论你再读多少遍,读到都还是 0。


如果管道关闭,我们还能像里面写数据吗?


是的,不能再往管道写数据了。


如果我们往管道里面写 n 个,那么关闭管道之后,再去读管道,就能再读 n 个,超过 n 个就读到的是默认值 0。

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

Regan Yue

关注

还未添加个人签名 2020.08.12 加入

还未添加个人简介

评论

发布
暂无评论
管道(Channel)的读取与写入「让我们一起Golang」