写点什么

Golang 协程之了解管道的缓存能力

用户头像
Regan Yue
关注
发布于: 3 小时前
Golang协程之了解管道的缓存能力

Golang 协程之了解管道的缓存能力

我们之前讲过,当使用 make 建立管道时,第二个参数为零,就证明这个管道是无缓存能力的管道。只要没人写就永远读不出来,只要没人读就永远写不进去。例如:


ch := make(chan int,0)
复制代码


管道的缓冲区能被初始化为指定的缓冲区容量。 如果为零,或者省略了大小,则该通道是无缓冲的。


如果将第二个参数改为 8(这里可以为任意大小),这就说明缓存能力为 8,即使不读,也能写入 8 个元素。


package main
import ( "fmt" "time")
func main() { //The channel's buffer is initialized with the specified buffer capacity. //If zero, or the size is omitted, the channel is unbuffered. ch := make(chan int,0)
go func() { ch <- 123 fmt.Println("数据已写入") }()
go func() { time.Sleep(2*time.Second) x:= <- ch fmt.Println("数据已读出",x) }()
time.Sleep(5*time.Second) fmt.Println("Game Over!")}
复制代码


这段代码在运行过程中,由于一条协程在写入管道缓冲区,另一条协程在读取管道的缓冲区,但是读取管道缓冲区的那条协程会 sleep 两秒,所以在前两秒另一条写入管道缓冲区的协程也不能写入。


如果让写入管道缓冲区的那条协程 sleep 两秒,那么前两秒另一条读取管道缓冲区的协程也不能读取数据。


如果一个缓冲区大小为 3 的管道,写入 4 个值,那么第 4 个值就写入不了,运行结果是这样的:


写入1写入2写入3
复制代码


下面我们来看一看管道内的元素个数及它的缓存能力吧:


package main
import ( "fmt" "time")
func main101() { ch := make(chan int,3)
go func() { ch <- 1 fmt.Println("写入1") ch <- 2 fmt.Println("写入2") ch <- 3 fmt.Println("写入3") //管道的缓冲区已经存满,不能再写入! ch <- 4 fmt.Println("写入4") }() time.Sleep(5 * time.Second)}
func main() { ch := make(chan int,3) fmt.Println("元素的个数为",len(ch),"缓存能力为",cap(ch));
ch <- 123 fmt.Println("元素的个数为",len(ch),"缓存能力为",cap(ch)); ch <- 123 fmt.Println("元素的个数为",len(ch),"缓存能力为",cap(ch)); ch <- 123 fmt.Println("元素的个数为",len(ch),"缓存能力为",cap(ch)); }
复制代码


运行结果是


元素的个数为 0 缓存能力为 3元素的个数为 1 缓存能力为 3元素的个数为 2 缓存能力为 3元素的个数为 3 缓存能力为 3fatal error: all goroutines are asleep - deadlock!
goroutine 1 [chan send]:main.main() E:/main.go:36 +0x4e5
Process finished with exit code 2
复制代码


我们可以看到管道的缓存能力是没有变化的,但是存入的元素个数是在变化的。


我们可以看到这里出现了死锁,这里主协程永远无法继续执行。


我们再来了解一下管道的有关知识。


据了解,管道是建立在堆上面的。使用 make 函数返回的是指针,这就是为什么我们能够在函数之间传递管道,不需要传递指向管道的指针。


ch := make(chan int,0)
复制代码


使用 make 创建一个管道只能传输同一类型的数据,建立一个管道时需要指定一个数据类型,不允许通过一个管道传输多种类型的数据。

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

Regan Yue

关注

还未添加个人签名 2020.08.12 加入

还未添加个人简介

评论

发布
暂无评论
Golang协程之了解管道的缓存能力