网站首页 > 技术文章 正文
网上对于channel的解析有很多,我就分享一下个人理解。感觉channel类似 linux 里面管道,IO流的概念。它有输入和输出的概念,同时会发生阻塞。
无缓存的channel类型下面的图片,输入和输出直接经过channel。
func main() {
ch := make(chan struct{}) // 无缓冲区的channel
go func() {
ch <- struct{}{} // 协程 阻塞挂起 直到有接收方
}()
for {
fmt.Println(runtime.NumGoroutine())
time.Sleep(time.Second)
}
}
有缓冲区的channel,类似下面的这个图,拥有容量有线的环形元素数组和长度不限制的存放阻塞数据的队列。
有几个需要注意的点
- channel没有流出,也就是接收方。会阻塞挂起,(在执行)
- 拥有缓冲区的channel,缓冲区可以接收数据,不超容量不会阻塞
我们可以从channel的数据结构体上印证一下
type hchan struct {
qcount uint // 当前 channel 中存在多少个元素;
dataqsiz uint // size of the circular queue
buf unsafe.Pointer // channel 中用于存放元素的环形缓冲区;
elemsize uint16
closed uint32
elemtype *_type // element type
sendx uint // send index
recvx uint // receive index
recvq waitq // 因接收而陷入阻塞的协程队列;
sendq waitq // 因发送而陷入阻塞的协程队列;
lock mutex // 锁
}
关于阻塞
发送和接收channel超出容量,都会陷入阻塞。看一下怎么发送的阻塞。主要就是 gopark的调用。
gopark 将 g 变为阻塞态 waiting (g与m解绑, g等待新一轮的调度)
// No stack splits between assigning elem and enqueuing mysg
// on gp.waiting where copystack can find it.
mysg.elem = ep
mysg.waitlink = nil
mysg.g = gp
mysg.isSelect = false
mysg.c = c
gp.waiting = mysg
gp.param = nil
c.sendq.enqueue(mysg)
// Signal to anyone trying to shrink our stack that we're about
// to park on a channel. The window between when this G's status
// changes and when we set gp.activeStackChans is not safe for
// stack shrinking.
atomic.Store8(&gp.parkingOnChan, 1)
gopark(chanparkcommit, unsafe.Pointer(&c.lock), waitReasonChanSend, traceEvGoBlockSend, 2)
// Ensure the value being sent is kept alive until the
// receiver copies it out. The sudog has a pointer to the
// stack object, but sudogs aren't considered as roots of the
// stack tracer.
KeepAlive(ep)
// someone woke us up.
if mysg != gp.waiting {
throw("G waiting list is corrupted")
}
gp.waiting = nil
gp.activeStackChans = false
closed := !mysg.success
gp.param = nil
if mysg.releasetime > 0 {
blockevent(mysg.releasetime-t0, 2)
}
什么时候再变成可调度,我们看一下源码的 send channel 位置。会有调用 goready,将g由waiting阻塞态变为可调度,等待被调度。走gmp调度处理。
select为什么能监听channel
如果go协程已经陷入阻塞状态了,那么select为什么还能监听到channel呢?如果有select监听的时候,会进入一个类似自旋的状态,没有真正的阻塞。非阻塞模式。
默认情况下,读/写 channel 都是阻塞模式,只有在 select 语句组成的多路复用分支中,与 channel 的交互会变成非阻塞模式:
以上就是我关于channel的理解。文字描述有限,后面会有一次视频的描述。
猜你喜欢
- 2024-10-25 什么是喉梗阻 反流性食管炎嗓子疼怎么办
- 2024-10-25 阻塞列队详解!让你轻松理解阻塞列队
- 2024-10-25 【健康科普】认识阻塞性睡眠呼吸暂停低通气综合征
- 2024-10-25 气象科普|阻塞高压为何方神圣?后期它将给我国制造多轮冷空气
- 2024-10-25 非阻塞算法CAS 非阻塞函数
- 2024-10-25 为什么网络 I/O 会被阻塞?I/O 到底是什么?
- 2024-10-25 如何用Java设计阻塞队列,再说说ArrayBlocking和LinkedBlocking
- 2024-10-25 使用 Python Socket 实现非阻塞 I/O入门讲解
- 2024-10-25 梗阻性无精子症:多种选择,何为最佳?
- 2024-10-25 焦耳小偷 一个神奇的电路 焦耳小偷电路需要注意的地方
你 发表评论:
欢迎- 最近发表
-
- 吴谨言专访大反转!痛批耍大牌后竟翻红,六公主七连发力显真诚
- 港股2月28日物业股涨幅榜:CHINAOVSPPT涨1.72%位居首位
- 港股2月28日物业股午盘:CHINAOVSPPT涨1.72%位居首位
- 港股3月2日物业股涨幅榜:CHINAOVSPPT涨1.03%位居首位
- 港股3月2日物业股午盘:CHINAOVSPPT涨1.03%
- 天赋与心痛的背后:邓鸣贺成长悲剧引发的深刻反思
- 冯小刚女儿徐朵追星范丞丞 同框合照曝光惹人羡,回应网友尽显亲民
- “资本大佬”王冉:51岁娶小17岁童瑶,并承诺余生为娇妻保驾护航
- 港股3月2日物业股午盘:CHINAOVSPPT涨1.03%位居首位
- 「IT之家开箱」vivo S15 图赏:双镜云窗,盛夏风光
- 标签列表
-
- oraclesql优化 (66)
- 类的加载机制 (75)
- feignclient (62)
- 一致性hash算法 (71)
- dockfile (66)
- 锁机制 (57)
- javaresponse (60)
- 查看hive版本 (59)
- phpworkerman (57)
- spark算子 (58)
- vue双向绑定的原理 (68)
- springbootget请求 (58)
- docker网络三种模式 (67)
- spring控制反转 (71)
- data:image/jpeg (69)
- base64 (69)
- java分页 (64)
- kibanadocker (60)
- qabstracttablemodel (62)
- java生成pdf文件 (69)
- deletelater (62)
- com.aspose.words (58)
- android.mk (62)
- qopengl (73)
- epoch_millis (61)
本文暂时没有评论,来添加一个吧(●'◡'●)