golang从channel读数据的各种情况
<h3>用var定义channel且不make</h3>
<pre><code class="lang-go hljs">wg <span class="token operator">:=</span> sync<span class="token punctuation">.</span>WaitGroup<span class="token punctuation">{</span><span class="token punctuation">}</span>
<span class="token keyword">var</span> ch <span class="token keyword">chan</span> <span class="token builtin">string</span>
read <span class="token operator">:=</span> <span class="token keyword">func</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
fmt<span class="token punctuation">.</span><span class="token function">Println</span><span class="token punctuation">(</span><span class="token string">"reading"</span><span class="token punctuation">)</span>
s <span class="token operator">:=</span> <span class="token operator"><-</span>ch
fmt<span class="token punctuation">.</span><span class="token function">Println</span><span class="token punctuation">(</span><span class="token string">"read:"</span><span class="token punctuation">,</span> s<span class="token punctuation">)</span>
wg<span class="token punctuation">.</span><span class="token function">Done</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span>
write <span class="token operator">:=</span> <span class="token keyword">func</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
fmt<span class="token punctuation">.</span><span class="token function">Println</span><span class="token punctuation">(</span><span class="token string">"writing"</span><span class="token punctuation">)</span>
s <span class="token operator">:=</span> <span class="token string">"t"</span>
ch <span class="token operator"><-</span> s
fmt<span class="token punctuation">.</span><span class="token function">Println</span><span class="token punctuation">(</span><span class="token string">"write:"</span><span class="token punctuation">,</span> s<span class="token punctuation">)</span>
wg<span class="token punctuation">.</span><span class="token function">Done</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span>
wg<span class="token punctuation">.</span><span class="token function">Add</span><span class="token punctuation">(</span><span class="token number">2</span><span class="token punctuation">)</span>
<span class="token keyword">go</span> <span class="token function">read</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token keyword">go</span> <span class="token function">write</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
fmt<span class="token punctuation">.</span><span class="token function">Println</span><span class="token punctuation">(</span><span class="token string">"waiting"</span><span class="token punctuation">)</span>
wg<span class="token punctuation">.</span><span class="token function">Wait</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</code></pre>
输出: 这种情况并不是报错空指针,而是死锁。加上make看看 输出 这种情况没什么毛病,之所以先输出的read,是因为IO机制。下面给写加上for 输出 报错说所有的协程都睡着,意思就是runtime发现没有能拿来调度的协程了,报错退出。如果是在大项目中,这里则会阻塞,runtime会调度其他可运行的协程。下面把for移到读操作上。 输出 跟上面现象基本一样,不再赘述,然后给俩操作都加上for 输出 结果当然就是死循环了,这个很好理解。接下来才是本文的重点:读数据的第二个参数。我们先保持其他的都不动,在读的时候接收第二个返回值。 输出 可以看出来,这第二个返回值是个bool类型,目前全都是true。那么什么时候会是false呢,把channel关上试试。为了更直观,把字符串的长度一起输出 输出 接下来就是很规律的死循环了。这样是不是可以猜测,从已经close的channle读数据,会读到该数据类型的零值,且第二个返回值为false?再试试给channel加个buffer,先写完关上再开始读 输出 我们把写操作前的<code>go</code>关键字去了,并且在关闭channel之后加了log。可以很清晰的看到,先往channel里写了5次,然后close了,之后才有wait及read的log。并且前5个ok是true,后面循环输出false。现在我们可以得出结论当channel关闭且数据都读完了,再读数据会读到该数据类型的零值,且第二个返回值为false。下面再套上select 输出 很明显跟上面现象一致,如果忘了关闭channel呢? 输出 又睡着了,然后报错。跟上面情况一样,如果是在大项目中,runtime会调度其他可运行的协程。最后来总结一下怎么操作才算优(sao)雅(qi)。 您可能感兴趣的文章:
golang channel的使用以及调度原理
【文末有惊喜!】一文读懂golang channel
图解 Go 并发编程
golang知识点
Go并发编程——channel
图解Go的channel底层原理
Golang 中的 Goroutine 调度原理与 Chanel 通信
协程调度时机二:Channel读写
go语言并发编程
golang goroutine 通知_深入golang之---goroutine并发控制与通信