网站首页 > 技术文章 正文
网上对于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 焦耳小偷 一个神奇的电路 焦耳小偷电路需要注意的地方
你 发表评论:
欢迎- 02-26Docker目录说明之 /var/lib/docker
- 02-26家用nas最常用的docker容器及部署方法
- 02-26Docker快速上手笔记
- 02-26怎样在Python中操作Docker容器?
- 02-26手把手教你搭建LLM模型知识库,开启AI智慧大门
- 02-26Docker容器是个啥?和VM有什么区别?
- 02-26Docker入门指南:从新手到容器大师
- 02-26带你一文搞懂 Docker
- 最近发表
- 标签列表
-
- 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)
本文暂时没有评论,来添加一个吧(●'◡'●)