Go进阶原理杂记

切片原理

Pointer 是指向一个数组的指针,len 代表当前切片的长度,cap 是当前切片的容量。(cap 总是大于等于 len 的)
Go进阶原理杂记_第1张图片
Go进阶原理杂记_第2张图片

map原理

  • hmap(a header for a go map)结构:
    最重要的是:buckets散列表指针!
    其中B:2^B就是[]bmap长度

Go进阶原理杂记_第3张图片

  • bmap(a bucket for a Go map通常叫其bucket)结构:
  1. buckets指针指向一个一维数组,也就是bucket集合([]bmap)
    Go进阶原理杂记_第4张图片

  2. 集合槽点数据结构为bmap
    每个bucket最多存放8个key-value
    Go进阶原理杂记_第5张图片

key-value是分开存的:可以消除padding(内存对齐)带来的空间浪费。
在这里插入图片描述

  1. 数据存储过程:
    key得到hash值 ===> hash值的低位算出槽点 ===> hash高位算出bucket链中哪个bucket
    Go进阶原理杂记_第6张图片

Go进阶原理杂记_第7张图片

map扩容(懒迁移)

扩容因子公式是:map元素个数 / []bmap数组长度,阈值是6.5。
当达到扩容要求,将产生一个新的二倍bucket数组

注意:并不是立刻把旧的数组中的元素转义到新的bucket当中,而是,只有当访问到具体的某个bucket的时候,会把bucket中的数据转移到新的bucket中。

Go进阶原理杂记_第8张图片

channel原理

环形队列+互斥锁

Go进阶原理杂记_第9张图片

回想:上面三种是特殊数据类型,常使用make()函数创建!


sync.Map

互斥锁 + 原子类

// 封装的线程安全的map
type Map struct {
	// lock
	mu Mutex

	// 实际是readOnly这个结构
	// 一个只读的数据结构,因为只读,所以不会有读写冲突。
	read atomic.Value // readOnly

	dirty map[interface{}]*entry

	// 当从Map中读取entry的时候,如果read中不包含这个entry,会尝试从dirty中读取,这个时候会将misses加一
	misses int
}

defer原理

品:无论defer多少,最终defer的变量值都是按照执行顺序最新的值

func main() {
	fmt.Println(f(1,2)) #102
}

func f(x, y int) int {
	defer func() {
		y = 200
		fmt.Println(x,y) #100 200
	}()
	x = 100
	return x+y
}

本质原因是return xxx语句并不是一条原子指令,defer被插入到了赋值(方法将值返回) 与 ret(方法弹出栈)之间。

goroutine的控制结构中,有一张表记录defer,调用runtime.deferproc时会将需要defer的表达式记录在表中,而在调用runtime.deferreturn的时候,则会依次从defer表中出栈并执行

你可能感兴趣的:(Go进阶,数据结构,go)