如何使用
- channel在<-左边 表示向channel发送数据
- channel在<-右边 表示从channel接收数据
- close(channelName) 关闭一个channel
|
|
Channel的关闭
- 关闭一个未初始化(nil) 的 channel 会产生 panic
- 重复关闭同一个 channel 会产生 panic
- 向一个已关闭的 channel 中发送消息会产生 panic
- 从一个已关闭的 channel 中读取消息永远不会阻塞,并且会返回一个为 false 状态,可以用它来判断 channel 是否关闭,close操作是对写入的关闭,但仍然可以读取,若消息均已读出,则会读到类型的初始值
|
|
缓冲区
- make创建通道时,指定通道的大小时,称为有缓冲通道,反之无缓冲区
- 无缓冲区或者缓冲区用完,写入一次,就要等待对方读取一次,否则无法继续写入阻塞住,同理读取不出来也会阻塞住
|
|
- 可以用len函数查看channel的已用大小, 用cap查看channel的缓存大小
|
|
单向通道
- 为了限制channel滥用,禁止其进行读取或者写入操作,让函数具有更高的单一原则,封装性
|
|
作用
- 同步: 依靠阻塞的特性 做多个goroutine之间的锁
|
|
- 定时器
|
|
- 通信: Channel是goroutine之间通信的通道,用于goroutine之间发消息和接收消息
|
|
- Select多路复用(I/O多路复用,I/O就是指的我们网络I/O,多路指多个TCP连接(或多个Channel),复用指复用一个或少量线程。串起来理解就是很多个网络I/O复用一个或少量的线程来处理这些连接)
- 对channel的read, write,close, 超时事件等进行监听,
- 同时触发事件会随机执行一个
- 阻塞在多个channel上,对多个channel的读/写事件进行监控
|
|
内部细节
数据结构
|
|
- channel 的主要组成有:
- 一个环形数组实现的循环队列, 用于存储消息元素
- recvq和sendq两个链表实现的 goroutine 等待队列, 用于存储阻塞在 recv 和 send 操作上的 goroutine
- 一个互斥锁,用于各个属性变动的同步
主要函数功能
- makechan: 开辟一快连续内存区域存储消息元素
|
|
- send chan<-
- 如果等待接收队列recvq不为空,说明缓冲区中没有数据或者没有缓冲区,此时直接从recvq取出G,并把数据写入,最后把该G唤醒
- 如果缓冲区中有空余位置,将数据写入缓冲区
- 如果缓冲区中没有空余位置,将待发送数据写入G,将当前G加入sendq,进入睡眠,等待被读goroutine唤醒;
|
|
- recv <-chan
- sendq不为空 获取链表的头一个first_g
- 缓存无数据,将first_g消息复制给当前请求的g,并激活first_g
- 缓存有数据, 缓存队列 出列消息给当前请求的g,并将first_g数据加入缓存队列,first_g激活
- 缓存队列有数据将数据出队 复制给当前请求的g
- 缓存队列无数据将调用此chan的当前g加入recvq链表并设置休眠
- sendq不为空 获取链表的头一个first_g
|
|
- close: 设置关闭符号为1,唤醒recvq和sendq的g
|
|