切片原理
Pointer 是指向一个数组的指针,len 代表当前切片的长度,cap 是当前切片的容量。(cap 总是大于等于 len 的)
map原理
hmap
(a header for a go map
)结构:
最重要的是:buckets散列表指针!
其中B:2^B
就是[]bmap
长度
bmap
(a bucket for a Go map
通常叫其bucket)结构:
-
buckets指针指向一个一维数组,也就是bucket集合([]bmap)
-
集合槽点数据结构为
bmap
每个bucket
最多存放8个key-value
key-value
是分开存的:可以消除padding(内存对齐)带来的空间浪费。
- 数据存储过程:
key得到hash值 ===> hash值的低位算出槽点 ===> hash高位算出bucket链中哪个bucket
map扩容(懒迁移)
扩容因子公式是:map元素个数 / []bmap数组长度
,阈值是6.5。
当达到扩容要求,将产生一个新的二倍bucket数组
注意:并不是立刻把旧的数组中的元素转义到新的bucket当中,而是,只有当访问到具体的某个bucket的时候,会把bucket中的数据转移到新的bucket中。
channel原理
环形队列+互斥锁
回想:上面三种是特殊数据类型,常使用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表中出栈并执行。