gc 垃圾回收;
channel
-
channel 数据接口 和流程
-
源码阅读: make 、send 、receive
type hchan struct {
qcount uint // 环形队列数据量
dataqsiz uint // 环形队列的大小
buf unsafe.Pointer //环形队列指针,内存环形队列,避免直线队列删除空间浪费问题
elemsize uint16 // 元素内存大小
closed uint32 // 关闭状态标示
elemtype *_type // 元素类型
sendx uint //发送索引位置
recvx uint // 接收索引位置
recvq waitq // 接收等待队列(g)
sendq waitq //发送等待队列(g)
lock mutex //并发控制
}
type waitq struct {
first *sudog //等待双向链表队列
last *sudog//?
}
// make
func makechan(t *chantype, size int) *hchan {
elem := t.elem
// 内存大小计算
mem, overflow := math.MulUintptr(elem.size, uintptr(size))
switch {
case mem == 0:
// 无缓存队列
c = (*hchan)(mallocgc(hchanSize, nil, true))
c.buf = c.raceaddr()
case elem.ptrdata == 0:
// 有缓存队列
c = (*hchan)(mallocgc(hchanSize+mem, nil, true))
// 指针指向内存
c.buf = add(unsafe.Pointer(c), hchanSize)
}
c.elemsize = uint16(elem.size)
c.elemtype = elem
c.dataqsiz = uint(size)
return c
}
// send: c<-ep (groutine send 数据)
func chansend(c *hchan, ep unsafe.Pointer, block bool, callerpc uintptr) bool {
lock(&c.lock)
// 接收队列有空闲,则直接发送
if sg := c.recvq.dequeue(); sg != nil {
send(c, sg, ep, func() { unlock(&c.lock) }, 3)
return true
}
// 否则,如果缓存队列没有满,则加入缓存
if c.qcount < c.dataqsiz {
qp := chanbuf(c, c.sendx)
typedmemmove(c.elemtype, qp, ep)
c.sendx++
if c.sendx == c.dataqsiz {
c.sendx = 0
}
c.qcount++
unlock(&c.lock)
return true
}
// 已满,且非阻塞,则直接返回
if !block {
unlock(&c.lock)
return false
}
// 阻塞,等待接受者结束,
gp := getg()
mysg := acquireSudog()
// 放入发送队列
c.sendq.enqueue(mysg)
// 释放g
releaseSudog(mysg)
return true
}
// receive (groutine get 数据)
func recv(c *hchan, sg *sudog, ep unsafe.Pointer, unlockf func(), skip int) {
if c.dataqsiz == 0 {
// 无缓存,则直接接受数据
recvDirect(c.elemtype, sg, ep)
} else {
// 获取待读取数据
qp := chanbuf(c, c.recvx)
typedmemmove(c.elemtype, qp, sg.elem)
c.recvx++
if c.recvx == c.dataqsiz {
c.recvx = 0
}
c.sendx = c.recvx // c.sendx = (c.sendx+1) % c.dataqsiz
}
// 唤醒g
goready(gp, skip+1)
}
map 底层数据结构和算法
- map 存储结构
- map的make、set 、get、range、keys 源码阅读
type hmap struct {
count int // map 的数据个数
flags uint8
B uint8 // 负荷系数 2^B 个数据量
noverflow uint16 //
hash0 uint32 // hash seed
buckets unsafe.Pointer // 桶的数组指针
oldbuckets unsafe.Pointer // 数据增长时,变换前的旧桶数组指针
nevacuate uintptr //
extra *mapextra // 额外 数据
}
type mapextra struct {
// 如果key 或 elem 不包含指针,才会使用当前结构,目的是避免gc 扫描 ,提高性能
overflow *[]*bmap
oldoverflow *[]*bmap
nextOverflow *bmap
}
type bmap struct {
tophash [bucketCnt]uint8
}
// 迭代器定义
type hiter struct {
key unsafe.Pointer // key
elem unsafe.Pointer // value
t *maptype // 类型
h *hmap // map 指针
buckets unsafe.Pointer // 所在桶
bptr *bmap // current bucket
overflow *[]*bmap // keeps overflow buckets of hmap.buckets alive
oldoverflow *[]*bmap // keeps overflow buckets of hmap.oldbuckets alive
startBucket uintptr // bucket iteration started at
offset uint8 //
wrapped bool //
B uint8
i uint8
bucket uintptr
checkBucket uintptr
}
slice、interface,mutex 底层原理;
调度模型
M:内核级线程
G:代表一个goroutine
P:Processor,处理器,用来管理和执行goroutine的。