golang 底层数据结构和算法源码阅读

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的。

WRITTEN BY:    陈贞

个人博客