golang 学习(三十)管道(channel)介绍以及应用
channel 是一种类型,一种引用类型
var 变量 chan 元素类型
声明的管道后需要使用 make 函数初始化之后才能使用
make(chan 元素类型, 容量)
管道有发送(send)、接收(recive)和关闭(close)三种操作
发送和接收都使用<-符号
关闭管道 close(ch)
关于关闭管道需要注意的事情是,只有在通知接收方 goroutine 所有的数据都发送完毕的时
候才需要关闭管道。管道是可以被垃圾回收机制回收的,它和关闭文件是不一样的,在结束
操作之后关闭文件是必须要做的,但关闭管道不是必须的。
关闭后的管道有以下特点:
无缓冲的管道:
如果创建管道的时候没有指定容量,那么我们可以叫这个管道为无缓冲的管道
无缓冲的管道又称为阻塞的管道
只要管道的容量大于零,那么该管道就是有缓冲的管道,管道的容量表示管道中能存放元素
的数量。就像你小区的快递柜只有那么个多格子,格子满了就装不下了,就阻塞了,等到别
人取走一个快递员就能往里面放一个。
有的时候我们会将管道作为参数在多个任务函数间传递,很多时候我们在不同的任务函数中 使用管道都会对其进行限制,比如限制管道在函数中只能发送或只能接收
<pre><code class="lang-go hljs"><span class="token comment">//定义双向管道</span> <span class="token keyword">var</span> myChan <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">int</span><span class="token punctuation">,</span><span class="token number">2</span><span class="token punctuation">)</span> <span class="token comment">//定义只读的channel</span> <span class="token keyword">var</span> readChan <span class="token operator">=</span> <span class="token function">make</span><span class="token punctuation">(</span><span class="token operator"><-</span><span class="token keyword">chan</span> <span class="token builtin">int</span><span class="token punctuation">,</span><span class="token number">2</span><span class="token punctuation">)</span> <span class="token operator"><-</span>readChan <span class="token operator"><-</span>readChan <span class="token comment">//定义只写的channel</span> <span class="token keyword">var</span> writeChan <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 operator"><-</span> <span class="token builtin">int</span><span class="token punctuation">,</span><span class="token number">2</span><span class="token punctuation">)</span> writeChan<span class="token operator"><-</span><span class="token number">10</span> writeChan<span class="token operator"><-</span><span class="token number">20</span> </code></pre> <h2>select 多路复用</h2> <ol><li>传统的方法在遍历管道时,如果不关闭会阻塞而导致 deadlock,在实际开发中,可能我们不好确定什么关闭该管道</li><li>Go 内置了 select 关键字,可以同时响应多个管道的操作</li><li>使用 select 语句能提高代码的可读性。• 可处理一个或多个 channel 的发送/接收操作。
• 如果多个 case 同时满足,select 会随机选择一个。
• 对于没有 case 的 select{}会一直等待,可用于阻塞 main 函数</li></ol><pre><code class="lang-go hljs"><span class="token keyword">func</span> <span class="token function">TestChan</span><span class="token punctuation">(</span>t <span class="token operator">*</span>testing<span class="token punctuation">.</span>T<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">//select 多路复用 在某些场景下我们需要同时从多个 channel接收数据,这个时候就可以用到select多路复用</span> <span class="token keyword">var</span> intChan <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">int</span><span class="token punctuation">,</span><span class="token number">10</span><span class="token punctuation">)</span> <span class="token keyword">var</span> stringChan <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">6</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">10</span><span class="token punctuation">;</span> i<span class="token operator"> </span> <span class="token punctuation">{</span> intChan<span class="token operator"><-</span>i <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">6</span><span class="token punctuation">;</span> i<span class="token operator"> </span> <span class="token punctuation">{</span> stringChan<span class="token operator"><-</span><span class="token string">"hello"</span> <span class="token operator"> </span>fmt<span class="token punctuation">.</span><span class="token function">Sprintf</span><span class="token punctuation">(</span><span class="token string">"%d"</span><span class="token punctuation">,</span>i<span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token comment">//使用select来获取channel里面的数据的时候不需要关闭channel,如果关闭会出现死循环</span> <span class="token keyword">for</span><span class="token punctuation">{</span> <span class="token keyword">select</span> <span class="token punctuation">{</span> <span class="token keyword">case</span> v<span class="token operator">:=</span><span class="token operator"><-</span>intChan<span class="token punctuation">:</span> fmt<span class="token punctuation">.</span><span class="token function">Printf</span><span class="token punctuation">(</span><span class="token string">"读取int值%v\n"</span><span class="token punctuation">,</span>v<span class="token punctuation">)</span> time<span class="token punctuation">.</span><span class="token function">Sleep</span><span class="token punctuation">(</span>time<span class="token punctuation">.</span>Millisecond<span class="token operator">*</span><span class="token number">50</span><span class="token punctuation">)</span> <span class="token keyword">case</span> v<span class="token operator">:=</span><span class="token operator"><-</span>stringChan<span class="token punctuation">:</span> fmt<span class="token punctuation">.</span><span class="token function">Printf</span><span class="token punctuation">(</span><span class="token string">"读取string值%v\n"</span><span class="token punctuation">,</span>v<span class="token punctuation">)</span> time<span class="token punctuation">.</span><span class="token function">Sleep</span><span class="token punctuation">(</span>time<span class="token punctuation">.</span>Millisecond <span class="token operator">*</span> <span class="token number">50</span><span class="token punctuation">)</span> <span class="token keyword">default</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">"结束"</span><span class="token punctuation">)</span> <span class="token keyword">return</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> </code></pre> <h2>Goroutine Recover 解决协程中出现的 Panic</h2> <pre><code class="lang-go hljs"><span class="token keyword">func</span> <span class="token function">sayNum</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">10</span><span class="token punctuation">;</span> i<span class="token operator"> </span> <span class="token punctuation">{</span> time<span class="token punctuation">.</span><span class="token function">Sleep</span><span class="token punctuation">(</span>time<span class="token punctuation">.</span>Second<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">"hello"</span><span class="token punctuation">,</span>i<span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token keyword">func</span> <span class="token function">test</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">//defer recover 处理异常</span> <span class="token keyword">defer</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">if</span> err<span class="token operator">:=</span><span class="token function">recover</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>err<span class="token operator">!=</span><span class="token boolean">nil</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">"程序异常"</span><span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">var</span> myMap <span class="token keyword">map</span><span class="token punctuation">[</span><span class="token builtin">int</span><span class="token punctuation">]</span><span class="token builtin">string</span> myMap<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token string">"hello world"</span> <span class="token punctuation">}</span> <span class="token keyword">func</span> <span class="token function">TestChan</span><span class="token punctuation">(</span>t <span class="token operator">*</span>testing<span class="token punctuation">.</span>T<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">go</span> <span class="token function">sayNum</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">go</span> <span class="token function">test</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">}</span> </code></pre>
您可能感兴趣的文章:
【文末有惊喜!】一文读懂golang channel
Go 语言为什么这么快,带你详细了解Golang CSP并发模型
图解 Go 并发编程
golang知识点
golang学习笔记(二)—— 深入golang中的协程
golang基础教程
golang 面试题(三)管道chan
golang channel的使用以及调度原理
字节跳动的 Go 语言面试会问哪些问题?
GO语言学习-并发