彻底搞懂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来表示

下一篇我们继续。

相关文章
|
7月前
muduo源码剖析之channel通道类
channel是muduo中的事件分发器,它只属于一个EventLoop,Channel类中保存着IO事件的类型以及对应的回调函数,每个channel只负责一个文件描述符,但它并不拥有这个文件描述符。channel是在epoll和TcpConnection之间起沟通作用,故也叫做通道,其它类通过调用channel的setCallbcak来和建立channel沟通关系。
111 0
|
7月前
|
设计模式 缓存 安全
一篇文章带你吃透Go语言的Atomic和Channel--实战方法
一篇文章带你吃透Go语言的Atomic和Channel--实战方法
108 0
|
7月前
|
Go
Go语言Channel进阶:巧妙运用超时机制
Go语言Channel进阶:巧妙运用超时机制
369 0
|
7月前
|
编解码 前端开发 网络协议
Netty Review - ObjectEncoder对象和ObjectDecoder对象解码器的使用与源码解读
Netty Review - ObjectEncoder对象和ObjectDecoder对象解码器的使用与源码解读
166 0
|
7月前
|
监控 网络协议 调度
Netty Review - 深入探讨Netty的心跳检测机制:原理、实战、IdleStateHandler源码分析
Netty Review - 深入探讨Netty的心跳检测机制:原理、实战、IdleStateHandler源码分析
430 0
|
缓存 移动开发 网络协议
TCP编写服务器,客户端以及遇到的两个问题,Socket,ServerScket 类,flush(),方法。以及多线程解决,及改进的线程池写法,IO多路复用的思想,C10K,C10M的阐述。万字超细
TCP编写服务器,客户端以及遇到的两个问题,Socket,ServerScket 类,flush(),方法。以及多线程解决,及改进的线程池写法,IO多路复用的思想,C10K,C10M的阐述。万字超细
|
程序员
难倒了80%程序员的题,谈谈你对Netty中,Pipeline工作原理的理解
1位工作8年的小伙伴,去某东面试IM部门,被问到这样一道面试题。说,请你谈一谈你对Netty Pipeline设计原理的理解。当时,他说只是用过Netty的Pipline,原理没有深入了解过,然后就没有然后了。
83 0
|
存储 缓存 Java
golang channel的创建、接受和发送原理讲透
golang channel的创建、接受和发送原理讲透
|
Web App开发 移动开发 前端开发
看完让你彻底搞懂Websocket原理
看完让你彻底搞懂Websocket原理
340 0
看完让你彻底搞懂Websocket原理
Netty - 探究零拷贝Zero Copy
Netty - 探究零拷贝Zero Copy
55 0