当前位置:网站首页>go笔记记录——channel
go笔记记录——channel
2022-08-02 00:13:00 【Meme_xp】
channel有什么特点
channel有2种类型:无缓冲、有缓冲
channel有3种模式:写操作模式(单向通道)、读操作模式(单向通道)、读写操作模式(双向通道)
channel有3种状态:未初始化、正常、关闭
注意点:
1.一个channel不能多次关闭,会导致painc
2.如果多个goroutine都监听同一个channel,那么 channel 上的数据都可能随机被某一个goroutine取走进行消费
3.如果多个goroutine监听同一个channel,如果这个channel被关闭,则所有goroutine都能收到退出信号
channel的底层实现原理
概念:
Go中的channel是一个队列,遵循先进先出的原则,负责协程之间的通信(Go语言提倡不要通过共享内存来通信,而要通过通信来实现内存共享,CSP(CommunicatingSequentiall Process)并发模型,就是通过goroutine和channel来实现的)
使用场景
停止信号监听
定时任务
生产方和消费方解耦
控制并发数
底层数据结构:
通过var声明或者make函数创建的channel变量是一个存储在函数栈帧上的指针,占用8个字节,指向堆上的hchan结构体
等待队列:
双向链表,包含一个头结点和一个尾结点
每个节点是一个sudog结构体变量,记录哪个协程在等待,等待的是哪个channel,等待发送/接收的数据在哪里
总结hchan结构体的主要组成部分有四个:
1.用来保存goroutine之间传递数据的循环数组:buf
2.用来记录此循环数组当前发送或接收数据的下标值:sendx和recvx
3.用于保存向该chan发送和从该chan接收数据被阻塞的goroutine队列: sendq和recvq
4.保证channel写入和读取数据时线程安全的锁:lock
有缓存channel和无缓存channel的区别
无缓冲:一个送信人去你家送信,你不在家他不走,你一定要接下信,他才会走。
有缓冲:一个送信人去你家送信,扔到你家的信箱转身就走,除非你的信箱满了,他必须等信箱有多余空间才会走。
无缓存的channel有发送者必须有接收者,否则会报错,发生阻塞
channel为什么是线程安全
为什么设计成线程安全?
不同协程通过channel进行递信,本身的使用场景就是多线程,为了保证数据的一致性,必须实现线程安全
如何实现线程安全的?
channel的底层实现中, hchan结构体中采用Mutex锁来保证数据读写安全。在对循环数组buf中的数据进行入队和出队操作时,必须先获取互斥锁,才能操作chrnel数据
channel如何控制groutine并发执行顺序
多个goroutine并发执行时,每一个goroutine抢到处理器的时间点不一致,gorouine的执行本身不能保证顺序。"即代码中先写的gorouine并不能保证先执行
思路:使用channel进行通信通知,用channel去传递信息,从而控制并发执行顺序
输出:
groutine1
groutine2
groutine3
duration:1//证明了我们是并行的,否则应该是三秒
channel的共享内存有什么优劣?
大部分语言通过共享内存来通信,go是通过通信来共享内存(csp)
优点:
帮助解耦生产者和消费者
缺点:
容易出现死锁
channel什么时候容易死锁
死锁:
1.单个协程永久阻塞
2.两个或两个以上的协程的执行过程中,由于竞争资源或由于彼此通信而造成的一种阻塞的现象。
channel死锁场景:
1.非缓存channel只写不读
2.非缓存channel读在写后面
3.缓存channel写入超过缓冲区数量
4.空读
- 多个协程互相等待
创建,发送,接受,关闭
创建
//带缓冲
ch := make( chan int,3)
//不带缓冲
ch := make(chan int)
创建时会做一些检查:
·元素大小不能超过64K ·
元素的对齐大小不能超过maxAlign也就是8字节。
计算出来的内存是否超过限制
创建时的策略:
如果是无缓冲的channel,会直接给hchan分配内存 ·
如果是有缓冲的channel,并且元素不包含指针,那么会为hchan和底层数组分配一段连续的地址·
如果是有缓冲的channel,并且元素包含指针,那么会为hchan和底层数组分别分配地址
发送
阻塞式:
调用chansend函数,并且block=true
ch <- 10
非阻塞式:
调用chansend函数,并且block=false
select {
case ch c<-10:
...
default
}
向channel中发送数据时大概分为两大块:检查和数据发送,数据发送流程如下
1.如果channel的读等待队列存在接收者goroutine
。将数据直接发送给第一个等待的goroutine,唤醒接收的goroutine
2.如果channel的读等待队列不存在接收者goroutine
。如果循环数组buf未满,那么将会把数据发送到循环数组buf的队尾
。如果循环数组buf已满,这个时候就会走阻塞发送的流程,将当前goroutine加入写等待队列,并挂起等待唤醒
接收
阻塞式四种:
非阻塞式:
向channel中接收数据时大概分为两大块,检查和数据发送,而数据接收流程如下:
1.如果channel的写等待队列存在发送者goroutine
。如果是无缓冲channel,直接从第一个发送者goroutine那里把数据拷贝给接收变量,唤醒发送的goroutine
。如果是有缓冲channel(已满),将循环数组buf的队首元素拷贝给接收变量,将第一个发送者goroutine的数据拷贝到buf循环数组队尾,唤醒发送的goroutine
2.如果channel的写等待队列不存在发送者goroutine:
。如果循环数组buf非空,将循环数组buf的队首元素拷贝给接收变量
。如果循环数组buf为空,这个时候就会走阻塞接收的流程,将当前goroutine加入读等待队列,并挂起等待唤醒
关闭
close(ch)
边栏推荐
- [Headline] Written test questions - minimum stack
- uni-app项目总结
- 短视频seo搜索优化主要内容
- Realize deletion - a specified letter in a string, such as: the string "abcd", delete the "a" letter in it, the remaining "bcd", you can also pass multiple characters to be deleted, and pass "ab" can
- 具有通信时延的多自主体系统时变参考输入的平均一致性跟踪
- 不了解SynchronousQueue?那ArrayBlockingQueue和LinkedBlockingQueue不会也不知道吧?
- c语言字符和字符串函数总结(二)
- nodeJs--mime模块
- [HCIP] BGP Small Experiment (Federation, Optimization)
- els 长条变形
猜你喜欢
uni-app项目总结
Don't know about SynchronousQueue?So ArrayBlockingQueue and LinkedBlockingQueue don't and don't know?
使用jOOQ将Oracle风格的隐式连接自动转换为ANSI JOIN
BGP 第一次实验
如何发现新的潜力项目?工具推荐
不要用jOOQ串联字符串
bgp aggregation reflector federation experiment
Knowing the inorder traversal of the array and the preorder traversal of the array, return the postorder history array
nodeJs--各种路径
22. The support vector machine (SVM), gaussian kernel function
随机推荐
玩转NFT夏季:这份工具宝典值得收藏
使用jOOQ将Oracle风格的隐式连接自动转换为ANSI JOIN
An overview of the most useful DeFi tools
BGP 第一次实验
Are test points the same as test cases?
Kotlin协程:创建、启动、挂起、恢复
短视频SEO搜索运营获客系统功能介绍
Multidimensional Correlation Time Series Modeling Method Based on Screening Partial Least Squares Regression of Correlation Variables
Redis的集群模式
els 方块变形判断。
BGP first experiment
JSP request对象功能详解说明
Don't know about SynchronousQueue?So ArrayBlockingQueue and LinkedBlockingQueue don't and don't know?
nodeJs--各种路径
Redis - message publish and subscribe
什么是低代码(Low-Code)?低代码适用于哪些场景?
基于数据驱动的变电站巡检机器人自抗扰控制
Difference between JSP out.print() and out.write() methods
IO流基础
Detailed explanation of JSP request object function