彻底搞懂channel原理(一)

简介: 彻底搞懂channel原理(一)

介绍


channel一些基础介绍这里就不过多涉及了,都1202年了,我不相信用过Go的人没用过channel

当然下图也涵盖了大部分使用姿势。


1668511932082.jpg


有一道使用channel进行任务编排的经典的题。题目如下:

有四个goroutine编号为 1、2、3、4。每秒钟会有一goroutine打印自己的编号。请你实现这个程序,让输出的编号总是按照 1、2、3、4、1、2、3、4、……的顺序打印出来。就像这样,


0.gif


可以自己先思考下,代码也可以通过后台回复击鼓传花获取


原理解析


从一个简单的例子说起

创建一个main.go文件,代码如下


1668511972288.jpg


我们来看看这段代码编译以后长啥样

想得到go程序的汇编代码并不难

可以使用go tool compile -N -l -S main.go生成汇编代码


1668511983165.jpg


或者使用go tool compile -N -l main.go先编译出代码,然后再使用go tool objdump main.o反汇编出代码

还可以通过go build -gcflags -S main.go同样可以得到汇编的代码


上面两种我就不演示了,可以自行实验。他们之中flag的具体含义也可以自行了解。

如果你觉得上面要自己敲代码比较麻烦,我推荐一个更加直接可视化的工具。


1668511997588.jpg


综上,从编译的代码我们可以看出,上述初始化一个channel,ch :=make(chanstruct{})

实际上调用的是runtime.makechan


1668512020214.jpg


从函数中,我们能知道最终返回一个runtime.hchan的指针

runtime.hchan结构


1668512044614.jpg


我们先来解释hchan结构体各个字段的含义,之后在案例介绍中会更加详细的说明他们的作用。


1668512062179.jpg


先来看qcountdataqsiz有什么区别?

你去银行办事,银行有5个办事窗口,那么dataqsiz就等于5。在这里体现的是channel的容量为5。去银行的时候,当前有3个窗口有人正在办事,那么qcount就等于3,体现channel当前有3个数据元素。那么此时银行还可以再接待2个客户,对应还可以往channel发送2个数据元素

其他字段现在看看说明就行了,后面会细讲。


到这里我们就知道创建一个channel本质上就是得到一个runtime.hchan的指针后续对此chan的操作,无非就是对结构体字段进行相对应的操作

同时我们也能猜出,为啥channel能在不同的g中传递消息,而对于使用者来说不用担心并发的问题。

其实就是hchan内部使用互斥锁来保证了并发安全

最后我们来看一下runtime.makechan函数核心实现,当然注释已经很明白了


1668512083102.jpg


可以看到创建的时候有一段switch分支代码,那么什么情况下会走对应的case呢?


1668512095614.jpg


根据上面的信息,我们可以得出

  • 如果创建一个无缓冲channel那么只需要为runtime.hchan本身分配一段内存空间即可。
  • 如果创建的缓冲channel存储的类型不是指针类型会为当前channel和存储类型元素的缓冲区,分配一块连续的内存空间
  • 在默认情况下(缓冲channel存储类型包含指针)会单独为runtime.hchan和缓冲区分配内存。


总结


这篇我们主要介绍了如何获取go程序的汇编代码,通过汇编代码知道创建channel的具体函数runtime.makechan

同时我们还知道不同的创建姿势会导致走向不同的内存空间分配逻辑。

最后通过创建函数我们知道channel在程序运行时是使用runtime.hchan来表示

下一篇我们继续。

相关文章
|
8月前
muduo源码剖析之channel通道类
channel是muduo中的事件分发器,它只属于一个EventLoop,Channel类中保存着IO事件的类型以及对应的回调函数,每个channel只负责一个文件描述符,但它并不拥有这个文件描述符。channel是在epoll和TcpConnection之间起沟通作用,故也叫做通道,其它类通过调用channel的setCallbcak来和建立channel沟通关系。
117 0
|
算法 C++ 容器
C++初阶之一篇文章教会你queue和priority_queue(理解使用和模拟实现)(下)
优先队列是一种容器适配器,根据严格的弱排序标准,它的第一个元素总是它所包含的元素中最大的。 此上下文类似于堆,在堆中可以随时插入元素,并且只能检索最大堆元素(优先队列中位于顶部的元素)。 优先队列被实现为容器适配器,容器适配器即将特定容器类封装作为其底层容器
|
8月前
|
设计模式 缓存 安全
一篇文章带你吃透Go语言的Atomic和Channel--实战方法
一篇文章带你吃透Go语言的Atomic和Channel--实战方法
133 0
|
8月前
|
Go
Go语言Channel进阶:巧妙运用超时机制
Go语言Channel进阶:巧妙运用超时机制
393 0
|
8月前
|
SQL 关系型数据库 MySQL
搞懂connectTimeout和socketTimeout的区别
搞懂connectTimeout和socketTimeout的区别
410 0
|
存储 C++ 容器
C++初阶之一篇文章教会你queue和priority_queue(理解使用和模拟实现)(上)
队列是一种容器适配器,专门用于在FIFO上下文(先进先出)中操作,其中从容器一端插入元素,另一端提取元素。
|
Web App开发 移动开发 前端开发
看完让你彻底搞懂Websocket原理
看完让你彻底搞懂Websocket原理
360 0
看完让你彻底搞懂Websocket原理
|
存储 缓存 Java
golang channel的创建、接受和发送原理讲透
golang channel的创建、接受和发送原理讲透
|
存储 开发者
彻底搞懂函数,读这篇文章就够了
如果你之前使用过任何一门编程语言,那么对于你来讲想必已经知道什么是函数,以及如何使用函数了,那你大可不必往下读了。这篇文章是写给新手看的,也就是说我假设你对于函数没有任何的概念。 我们就先从什么是函数来说起吧!
133 0
|
消息中间件 存储 分布式计算
MQ 概念介绍 / 配置以及原理 简书
文章目录 1、什么是MQ 2、MQ的多种产品 3、MQ的工作原理 4、ActiveMQ 的配置 5、ActiveMQ 的数据存储方式 6、ActiveMQ的主从服务 7、ActiveMQ的集群负载均衡 什么是MQ?Message Queue, 就是消息队列,MQ 经常会作为多系统当中的网络消息传输。是一种应用程序对应用程序的通信方式。也是WEB服务器的一种重要的第三方软件。
426 0
MQ 概念介绍 / 配置以及原理 简书