go channel

打印 上一主题 下一主题

主题 845|帖子 845|积分 2537

模型

三部分组成:
  1. 发送等待队列
  2. 接收等待队列
  3. 管道 缓存区
复制代码
定义

在 runtime 的chan.go中
  1. type hchan struct {
  2.         qcount   uint         
  3.         dataqsiz uint         
  4.         buf      unsafe.Pointer
  5.         elemsize uint16
  6.         elemtype *_type // element type
  7.     // 上面的这几个组成了一个环形缓存区
  8.         closed   uint32 // 关闭状态
  9.     // 下面4个组成了2个队列 g的
  10.         sendx    uint   // send index
  11.         recvx    uint   // receive index
  12.         recvq    waitq  // list of recv waiters
  13.         sendq    waitq  // list of send waiters
  14.         // lock protects all fields in hchan, as well as several
  15.         lock mutex  // 锁,用于在操作 channel的 元素时候,保证并发安全
  16. }
复制代码
特殊缓存区

  1. qcount  已经存储的个数
  2. dataqsiz  环形队列缓存的容量,即允许缓存的消息最大个数
  3. buf   指向这个缓存区的地址
  4. elemsize 元素的大小
  5. elemtype  元素的类型
复制代码
设计成这样,主要目的不需要gc来清理,因为环形机构,会自动把删除数据内存给占了。
环形缓存可以大幅降低GC的开销
两个队列

这里还要看下 waitq 的定义
  1. type waitq struct {
  2.           first *sudog
  3.           last  *sudog
  4. }
  5. // 在sema中也有用到,就g结构体的封装
  6. type sudog struct {
  7.         g *g
  8.         next *sudog
  9.         prev *sudog
  10.         elem unsafe.Pointer // 接受参数的地址
  11.     // 当是接收g时候,如果有缓存中有数据,直接把数据拷贝到这个地址
复制代码
}
注意:这里的sendx 并不是指向发送队列中的g,而且发送队列应该写入环形缓存区的index,
同理,recvx也是,指向接受数据的g,应该从缓冲区的那个index取数据

互斥锁
  1. lock mutex  
复制代码
互斥锁并不是排队发送/接收数据
不是让发送和接收队列来排队的,这些发送和接收数据的队列,休眠也不是在锁的sema里
互斥锁保护的hchan结构体本身
所以, Channel并不是无锁的
状态值
  1.         closed   uint32 // 关闭状态
复制代码
0为开启、1为关闭
  1. 当一个关闭的channel,再往里写或者重复关闭、就会panic。但是可以读。
复制代码
发送数据

[code]c
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

祗疼妳一个

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表