带缓存的管道(buffered channel)
上一节我们讨论的channel
都是不带缓存的,这里所谓的不带缓存的意思是写进去一个数据,就必须先读取走才能接着写下一个数据进去,因此也是阻塞的。
Golang中我们还可以创建带缓存的channel
,向带缓存的channel
中写数据时,只有写满缓存才会阻塞协程的执行;同样的,从带缓存的channel
中读数据时,只有缓存为空时,即已经没数据可读时才会阻塞协程的执行。
可以通过如下语法来创建带缓存的channel
:
这里的capacity
表示缓存容量,必须大于或等于1才有缓存,默认的不带缓存的channel
缓存容量为0。
带缓存channel
举例
channel
举例我们举个例子来体会下带缓存channel
的用法。
这里我们通过语句ch := make(chan string, 2)
创建了缓存容量为2的channel
。由于容量为2,我们可以向该channel
中写入2个数据而不阻塞协程的执行。我们写入了两个字符串,由于没有阻塞,因此后面的打印语句得以执行。该程序输出结果如下:
我们再看一个例子来加深下对带缓存channel
的理解。
这里我们创建一个缓存容量为2的channel
。开启了write
协程后,主协程暂停了2秒。这期间write
协程在并发执行,在write
协程内我们不断的向channel
内写入数据,但是由于channel
的容量为2,我们仅能先写进去2个数据,即0
和1
,然后该协程进入阻塞状态,直到channel
内的数据被读走。因此该程序先输出如下:
然后主协程暂停2秒后开始读取channel
内的数据,每读出一个数据主协程又要暂停2秒,这个暂停期间write
协程中发现channel
内多了一个缓存位置,便继续写入一个数据,然后缓存又变满,再次进入阻塞状态。该程序输出如下:
死锁
上一节我们已经介绍过死锁了:
如果某个
goroutine
向某个channel
发送数据,那么需要某个其他goroutine
接收该channel
的数据,否则会发送运行时错误:deadlock
。类似的,如果某个goroutine
正在等待从某个channel
中接收数据,那么需要某个其他goroutine
向该channel
中写入数据,否则也会发送运行时错误:deadlock
。
上一节我们讨论的channel
都是不带缓存的,因此前面的说法是成立的。对于带缓存的channel
,死锁
条件则是缓存满了,或者缓存空了。就是说,如果channel
缓存已经满了,再继续向channel
写入数据时,那么就需要存在某个其他goroutine
接收该channel
的数据,否则陷入死锁状态;如果channel
缓存已经空了,再继续从该channel
中读取数据时,需要存在某个其他goroutine
向该channel
中写入数据,否则陷入死锁状态。
这里我们向一个缓存容量为2的channel
中写入了3个数据。这时必须有某个goroutine
从该channel
中读取数据才行,但是并没有,因此陷入死锁状态。该程序执行报如下错误:
channel
长度 vs channel
容量
channel
长度 vs channel
容量channel
容量指的是channel
最多能缓存的数据个数,是我们用make
初始化channel
时的第二个参数。channel
长度指的是channel
当前时刻缓存的数据个数。
这里我们创建了一个容量为3的channel
,因此最多能缓存3个数据。接着我们写进去2个数据,这样缓存内就有2个数据,因此长度为2。然后又读取了1个数据,这时还剩下1个数据,因此长度为1。该程序执行结果如下:
Last updated
Was this helpful?