教程集 www.jiaochengji.com
教程集 >  Golang编程  >  golang教程  >  正文 golang从channel读数据的各种情况

golang从channel读数据的各种情况

发布时间:2022-01-22   编辑:jiaochengji.com
教程集为您提供golang从channel读数据的各种情况等资源,欢迎您收藏本站,我们将为您提供最新的golang从channel读数据的各种情况资源
<svg xmlns="http://www.w3.org/2000/svg" style="display: none;"><path stroke-linecap="round" d="M5,0 0,2.5 5,5z" id="raphael-marker-block" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0);"/></svg>

<h3>文章目录</h3> <ul><li><ul><li><ul><li>用var定义channel且不make</li><li>用var定义channel且make</li><li>直给写操作加for</li><li>直给读操作加for</li><li>读写都加for</li><li>读channel的第二个返回值</li><li>关闭channel继续读</li><li>写完然后关闭channel再开始读</li><li>加个select</li><li>channel未及时关闭</li><li>总结</li></ul></li></ul></li></ul>

<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>

输出:

<pre><code>waiting writing reading fatal error: all goroutines are asleep - deadlock! </code></pre>

这种情况并不是报错空指针,而是死锁。加上make看看

<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 operator">=</span> <span class="token function">make</span><span class="token punctuation">(</span><span class="token keyword">chan</span> <span class="token builtin">string</span><span class="token punctuation">)</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> </code></pre>

输出

<pre><code>waiting writing reading read: t write: t </code></pre>

这种情况没什么毛病,之所以先输出的read,是因为IO机制。下面给写加上for

<h3>
直给写操作加for</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 operator">=</span> <span class="token function">make</span><span class="token punctuation">(</span><span class="token keyword">chan</span> <span class="token builtin">string</span><span class="token punctuation">)</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> <span class="token keyword">for</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> <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> fmt<span class="token punctuation">.</span><span class="token function">Println</span><span class="token punctuation">(</span><span class="token string">"finish"</span><span class="token punctuation">)</span> </code></pre>

输出

<pre><code>waiting reading writing write: t writing read: t fatal error: all goroutines are asleep - deadlock! </code></pre>

报错说所有的协程都睡着,意思就是runtime发现没有能拿来调度的协程了,报错退出。如果是在大项目中,这里则会阻塞,runtime会调度其他可运行的协程。下面把for移到读操作上。

<h3>
直给读操作加for</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 operator">=</span> <span class="token function">make</span><span class="token punctuation">(</span><span class="token keyword">chan</span> <span class="token builtin">string</span><span class="token punctuation">)</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> <span class="token keyword">for</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> <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> fmt<span class="token punctuation">.</span><span class="token function">Println</span><span class="token punctuation">(</span><span class="token string">"finish"</span><span class="token punctuation">)</span> </code></pre>

输出

<pre><code>waiting reading writing write: t read: t reading fatal error: all goroutines are asleep - deadlock! </code></pre>

跟上面现象基本一样,不再赘述,然后给俩操作都加上for

<h3>
读写都加for</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 operator">=</span> <span class="token function">make</span><span class="token punctuation">(</span><span class="token keyword">chan</span> <span class="token builtin">string</span><span class="token punctuation">)</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> <span class="token keyword">for</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> <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> <span class="token keyword">for</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> <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> fmt<span class="token punctuation">.</span><span class="token function">Println</span><span class="token punctuation">(</span><span class="token string">"finish"</span><span class="token punctuation">)</span> </code></pre>

输出

<pre><code>waiting writing reading read: t write: t writing reading read: t reading write: t writing write: t writing ... </code></pre>

结果当然就是死循环了,这个很好理解。接下来才是本文的重点:读数据的第二个参数。我们先保持其他的都不动,在读的时候接收第二个返回值。

<h3>
读channel的第二个返回值</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 operator">=</span> <span class="token function">make</span><span class="token punctuation">(</span><span class="token keyword">chan</span> <span class="token builtin">string</span><span class="token punctuation">)</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> <span class="token keyword">for</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 punctuation">,</span> ok <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> ok<span class="token punctuation">)</span> <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> <span class="token keyword">for</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> <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> fmt<span class="token punctuation">.</span><span class="token function">Println</span><span class="token punctuation">(</span><span class="token string">"finish"</span><span class="token punctuation">)</span> </code></pre>

输出

<pre><code>waiting writing reading read: t true reading write: t writing write: t writing read: t true reading read: t true reading write: t ... </code></pre>

可以看出来,这第二个返回值是个bool类型,目前全都是true。那么什么时候会是false呢,把channel关上试试。为了更直观,把字符串的长度一起输出

<h3>
关闭channel继续读</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 operator">=</span> <span class="token function">make</span><span class="token punctuation">(</span><span class="token keyword">chan</span> <span class="token builtin">string</span><span class="token punctuation">)</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> <span class="token keyword">for</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 punctuation">,</span> ok <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> <span class="token function">len</span><span class="token punctuation">(</span>s<span class="token punctuation">)</span><span class="token punctuation">,</span> s<span class="token punctuation">,</span> ok<span class="token punctuation">)</span> <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> <span class="token keyword">for</span> i <span class="token operator">:=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator"><</span> <span class="token number">5</span><span class="token punctuation">;</span> i<span class="token operator"> </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> <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 function">close</span><span class="token punctuation">(</span>ch<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> fmt<span class="token punctuation">.</span><span class="token function">Println</span><span class="token punctuation">(</span><span class="token string">"finish"</span><span class="token punctuation">)</span> </code></pre>

输出

<pre><code>waiting writing reading read: 1 t true reading write: t writing write: t writing read: 1 t true reading read: 1 t true reading write: t writing write: t writing read: 1 t true reading read: 1 t true reading write: t read: 0 false reading read: 0 false reading read: 0 false ... </code></pre>

接下来就是很规律的死循环了。这样是不是可以猜测,从已经close的channle读数据,会读到该数据类型的零值,且第二个返回值为false?再试试给channel加个buffer,先写完关上再开始读

<h3>
写完然后关闭channel再开始读</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 operator">=</span> <span class="token function">make</span><span class="token punctuation">(</span><span class="token keyword">chan</span> <span class="token builtin">string</span><span class="token punctuation">,</span> <span class="token number">5</span><span class="token punctuation">)</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> <span class="token keyword">for</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 punctuation">,</span> ok <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> <span class="token function">len</span><span class="token punctuation">(</span>s<span class="token punctuation">)</span><span class="token punctuation">,</span> s<span class="token punctuation">,</span> ok<span class="token punctuation">)</span> <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> <span class="token keyword">for</span> i <span class="token operator">:=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator"><</span> <span class="token number">5</span><span class="token punctuation">;</span> i<span class="token operator"> </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> <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 function">close</span><span class="token punctuation">(</span>ch<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">"closed"</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 function">write</span><span class="token punctuation">(</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> 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> fmt<span class="token punctuation">.</span><span class="token function">Println</span><span class="token punctuation">(</span><span class="token string">"finish"</span><span class="token punctuation">)</span> </code></pre>

输出

<pre><code class="lang-go hljs">writing write<span class="token punctuation">:</span> t writing write<span class="token punctuation">:</span> t writing write<span class="token punctuation">:</span> t writing write<span class="token punctuation">:</span> t writing write<span class="token punctuation">:</span> t closed waiting reading read<span class="token punctuation">:</span> <span class="token number">1</span> t <span class="token boolean">true</span> reading read<span class="token punctuation">:</span> <span class="token number">1</span> t <span class="token boolean">true</span> reading read<span class="token punctuation">:</span> <span class="token number">1</span> t <span class="token boolean">true</span> reading read<span class="token punctuation">:</span> <span class="token number">1</span> t <span class="token boolean">true</span> reading read<span class="token punctuation">:</span> <span class="token number">1</span> t <span class="token boolean">true</span> reading read<span class="token punctuation">:</span> <span class="token number">0</span> <span class="token boolean">false</span> reading read<span class="token punctuation">:</span> <span class="token number">0</span> <span class="token boolean">false</span> reading read<span class="token punctuation">:</span> <span class="token number">0</span> <span class="token boolean">false</span> <span class="token operator">...</span> </code></pre>

我们把写操作前的<code>go</code>关键字去了,并且在关闭channel之后加了log。可以很清晰的看到,先往channel里写了5次,然后close了,之后才有wait及read的log。并且前5个ok是true,后面循环输出false。现在我们可以得出结论当channel关闭且数据都读完了,再读数据会读到该数据类型的零值,且第二个返回值为false。下面再套上select

<h3>
加个select</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 operator">=</span> <span class="token function">make</span><span class="token punctuation">(</span><span class="token keyword">chan</span> <span class="token builtin">string</span><span class="token punctuation">,</span> <span class="token number">5</span><span class="token punctuation">)</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> <span class="token keyword">for</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> <span class="token keyword">select</span> <span class="token punctuation">{</span> <span class="token keyword">case</span> s<span class="token punctuation">,</span> ok <span class="token operator">:=</span> <span class="token operator"><-</span>ch<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">"read:"</span><span class="token punctuation">,</span> <span class="token function">len</span><span class="token punctuation">(</span>s<span class="token punctuation">)</span><span class="token punctuation">,</span> s<span class="token punctuation">,</span> ok<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">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> <span class="token keyword">for</span> i <span class="token operator">:=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator"><</span> <span class="token number">5</span><span class="token punctuation">;</span> i<span class="token operator"> </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> <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 function">close</span><span class="token punctuation">(</span>ch<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">"closed"</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 function">write</span><span class="token punctuation">(</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> 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> fmt<span class="token punctuation">.</span><span class="token function">Println</span><span class="token punctuation">(</span><span class="token string">"finish"</span><span class="token punctuation">)</span> </code></pre>

输出

<pre><code>writing write: t writing write: t writing write: t writing write: t writing write: t closed waiting reading read: 1 t true reading read: 1 t true reading read: 1 t true reading read: 1 t true reading read: 1 t true reading read: 0 false reading read: 0 false reading read: 0 false ... </code></pre>

很明显跟上面现象一致,如果忘了关闭channel呢?

<h3>
channel未及时关闭</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 operator">=</span> <span class="token function">make</span><span class="token punctuation">(</span><span class="token keyword">chan</span> <span class="token builtin">string</span><span class="token punctuation">,</span> <span class="token number">5</span><span class="token punctuation">)</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> <span class="token keyword">for</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> <span class="token keyword">select</span> <span class="token punctuation">{</span> <span class="token keyword">case</span> s<span class="token punctuation">,</span> ok <span class="token operator">:=</span> <span class="token operator"><-</span>ch<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">"read:"</span><span class="token punctuation">,</span> <span class="token function">len</span><span class="token punctuation">(</span>s<span class="token punctuation">)</span><span class="token punctuation">,</span> s<span class="token punctuation">,</span> ok<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">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> <span class="token keyword">for</span> i <span class="token operator">:=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator"><</span> <span class="token number">5</span><span class="token punctuation">;</span> i<span class="token operator"> </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> <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 comment">//close(ch)</span> <span class="token comment">//fmt.Println("closed")</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 function">write</span><span class="token punctuation">(</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> 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> fmt<span class="token punctuation">.</span><span class="token function">Println</span><span class="token punctuation">(</span><span class="token string">"finish"</span><span class="token punctuation">)</span> </code></pre>

输出

<pre><code>writing write: t writing write: t writing write: t writing write: t writing write: t waiting reading read: 1 t true reading read: 1 t true reading read: 1 t true reading read: 1 t true reading read: 1 t true reading fatal error: all goroutines are asleep - deadlock! </code></pre>

又睡着了,然后报错。跟上面情况一样,如果是在大项目中,runtime会调度其他可运行的协程。最后来总结一下怎么操作才算优(sao)雅(qi)。

<h3>
总结</h3> <ul><li>对写的一方来说,一定记着及时关闭channel,避免出现协程泄露。虽然它占得资源少,省点电不香么。</li><li>对读的一方来说,除非十分确定数据的个数,最好是用for来读数据,省的在“管儿”里有“野数据”造成内存泄露。同时根据第二个返回值的真假来控制for循环,避免出现“无效工作量”</li></ul> 到此这篇关于“golang从channel读数据的各种情况”的文章就介绍到这了,更多文章或继续浏览下面的相关文章,希望大家以后多多支持JQ教程网!

您可能感兴趣的文章:
golang channel的使用以及调度原理
【文末有惊喜!】一文读懂golang channel
图解 Go 并发编程
golang知识点
Go并发编程——channel
图解Go的channel底层原理
Golang 中的 Goroutine 调度原理与 Chanel 通信
协程调度时机二:Channel读写
go语言并发编程
golang goroutine 通知_深入golang之---goroutine并发控制与通信

[关闭]
~ ~