Go 语言入门 1-管道的特性及实现原理

入坑 go 也快一年了,从今天开始会定期分享一下 Go 语言学习过程中的一些基础知识。

go 语言中的管道, 主要是用于协程之间的通信, 比 UNIX 的管道更加轻量和易用。

我们先看一下管道的 数据结构:

<span class="code-snippet_outer"><span class="code-snippet__attribute">type hchan struct {</span></span>
<span class="code-snippet_outer">&#xA0;&#xA0;<span class="code-snippet__attribute">gcount&#xA0;&#xA0;&#xA0;uint&#xA0;&#xA0;//&#xA0;&#x73AF;&#x5F62;&#x961F;&#x5217;&#x5269;&#x4F59;&#x5143;&#x7D20;&#x4E2A;&#x6570;</span></span>
<span class="code-snippet_outer">&#xA0;&#xA0;dataqsiz&#xA0;uint&#xA0;//&#xA0;&#x73AF;&#x5F62;&#x961F;&#x5217;&#x957F;&#x5EA6;</span>
<span class="code-snippet_outer">&#xA0;&#xA0;buf&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;unsafe.Pointer // &#x73AF;&#x5F62;&#x961F;&#x5217;&#x6307;&#x9488;</span>
<span class="code-snippet_outer">&#xA0;&#xA0;elemsize&#xA0;uint16  // &#x6BCF;&#x4E2A;&#x5143;&#x7D20;&#x5927;&#x5C0F;</span>
<span class="code-snippet_outer">&#xA0;&#xA0;closed&#xA0;&#xA0;&#xA0;uint32&#xA0;&#xA0;//&#xA0;&#x6807;&#x8BC6;&#x5173;&#x95ED;&#x72B6;&#x6001;</span>
<span class="code-snippet_outer">&#xA0;&#xA0;elemtype&#xA0;*_type&#xA0;&#xA0;// &#x5143;&#x7D20;&#x7C7B;&#x578B;</span>
<span class="code-snippet_outer">&#xA0;&#xA0;sendx&#xA0;&#xA0;&#xA0;&#xA0;uint&#xA0;&#xA0;&#xA0;//&#xA0;&#x4E0B;&#x4E00;&#x4E2A;&#x5143;&#x7D20;&#x5199;&#x5165;&#x65F6;&#x7684;&#x4E0B;&#x6807;</span>
<span class="code-snippet_outer">&#xA0;&#xA0;recvx&#xA0;&#xA0;&#xA0;&#xA0;uint&#xA0;&#xA0;&#xA0;//&#xA0;&#x4E0B;&#x4E00;&#x4E2A;&#x5143;&#x7D20;&#x8BFB;&#x53D6;&#x65F6;&#x7684;&#x4E0B;&#x6807;</span>
<span class="code-snippet_outer">&#xA0;&#xA0;recvq&#xA0;&#xA0;&#xA0;&#xA0;waitq  //  &#x7B49;&#x5F85;&#x8BFB;&#x6D88;&#x606F;&#x7684;&#x961F;&#x5217;</span>
<span class="code-snippet_outer">&#xA0;&#xA0;sendq&#xA0;&#xA0;&#xA0;&#xA0;waitq  // &#x7B49;&#x5F85;&#x5199;&#x6D88;&#x606F;&#x7684;&#x961F;&#x5217;</span>
<span class="code-snippet_outer">&#xA0;&#xA0;lock&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;mutex&#xA0;&#xA0;//&#xA0;&#x4E92;&#x65A5;&#x9501;&#xFF0C;&#xA0;&#x4FDD;&#x969C;&#x7BA1;&#x9053;&#x65E0;&#x6CD5;&#x5E76;&#x53D1;&#x8BFB;&#x5199;</span>
<span class="code-snippet_outer">}</span>

源码链接:

https://github.com/golang/go/blob/0d0193409492b96881be6407ad50123e3557fdfb/src/runtime/chan.go#L33

通过上述数据结构, 我们可以理解管道是由三部分组成的:

环形队列

读写等待队列

队列元素基本信息

从管道读取数据时, 如果管道 缓冲区为空或者 没有缓冲区, 那么当前协程就会阻塞, 然后 放入 recvq 队列中。

往管道写入数据时, 如果管道 缓冲区为空或者 缓冲区满了, 那么当前协程就会阻塞, 然后 放入 sendq 队列中。

读阻塞进程将被写入数据的新进程唤醒。

[En]

The read blocking process will be awakened by the new process of writing data.

写入阻塞进程将被读取数据的新进程唤醒。

[En]

The write blocking process will be awakened by the new process of reading data.

同时上述数据结构中, 我们可以看到一个管道中只能传递一种元素类型。 如果想数据类型动态化, 可以传递 interface。

管道的操作:

初始化有两种方式:

变量声明:

<span class="code-snippet_outer"><span class="code-snippet__keyword">var&#xA0;ch&#xA0;chan&#xA0;int&#xA0;&#xA0;</span></span>

使用 make:

<span class="code-snippet_outer"><span class="code-snippet__attribute">ch1&#xA0;:= make(chan string)  // &#x65E0;&#x7F13;&#x51B2;&#x7BA1;&#x9053;</span></span>
<span class="code-snippet_outer">ch1&#xA0;:=&#xA0;make(chan&#xA0;string&#xA0;<span class="code-snippet__number">3)  // &#x6709;&#x7F13;&#x51B2;&#x7BA1;&#x9053;</span></span>

管道的读写是通过操作符: 「

Original: https://www.cnblogs.com/guanjinglin/p/16646496.html
Author: 关靖霖
Title: Go 语言入门 1-管道的特性及实现原理

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/498529/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球