-
channel结构
- qcount:表明缓冲区元素的数量
- datasiz:表明缓冲区的容量大小
- elemtype、elemsize:chan的元素类型和元素大小,一旦声明就会固定下来
- buf:存放元素的循环队列
- sendx:循环队列发送元素的指针位置
- recvx:循环队列接收元素的指针位置
- sendq:buf满了再发送会阻塞当前协程,发送方阻塞队列
- recvq:buf空接收元素会阻塞协程,接收方阻塞队列
- closed:标志位,是否关闭
- lock:锁,接收发送关闭通过加锁完成
-
send(发送):
-
缓冲区空:
- 如果recq有队列等待接收(代表buf中无数据),会直接把数据给到接收写成,不会放入到buf中,减少了已拷贝
- 如果recq无队列,判断有无缓冲区
- 有缓冲区,会把数据放入到buf中
- 无缓冲区,会直接阻塞发送者
-
缓冲区满:会阻塞发送者,把当前协程加入到sendq中
-
如果chan已经close,在发送会报panic
-
-
recv(接受):
- 无缓冲区:会直接阻塞调用
- 有缓冲区:
- buf中有数据,会优先从buf中取
- buf中无数据,如果senq有等待队列,会直接从senq弹出一个sender,然后拷贝一个元素给到recv
- buf中无数据,而且senq无等待队列,会被阻塞进入到revq中
- 如果这个chan已经关闭,当buf中有元素的时候会直接返回buf元素和true,buf无元素,会返回elemtype累心的一个空值和false
-
close:close一个已经关闭的chabn会报panic
-
具体应用
-
数据传递:有 4 个 goroutine,编号为 1、2、3、4。每秒钟会有一个 goroutine 打印出它自己的编号,要求你编写程序,让输出的编号总是按照 1、2、3、4、1、2、3、4……这个顺序打印出来。
-
消息交流:chanel就是一个生产/消费者的模型,可以使用这个模拟一个消息队列
-
信号传递:最典型的是main方法里,通过接收关闭程序的信号量来实现优雅启停
sigChan := make(chan os.Signal, 1) // 监听 SIGINT、SIGTERM 和 SIGHUP 信号 signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM, syscall.SIGHUP) // 等待信号 sig := <-sigChan fmt.Printf("Received signal: %v\n", sig) -
任务编排:类似击鼓传花,一个groutine会完成部分任务,通过多个goroutine的协作,完成一个复杂的任务
-