重写redis组件
GO的优点
直接编译为二进制。没有虚拟化损失
自带运行环境、无需处理GC问题
一次编码可以使用多种平台
超强的并发支持和并发易用性
Go没有对象、没有类、没有继承
Go通过组合匿名字段来达到类似继承的效果
去除了面向对象中复杂而冗余的部分
保留了基本的面向对象的特性
使用Modules
- go get XXX
- go get XXX@0.13
内存对齐
runtime 的介绍
go的runtime被编译为用户程序的一部分,和程序一起运行
内存管理
GC
协程调度
屏蔽一定的系统调用的差异性的能力
一些go的关键字回转化为 runtime中的函数
词法分析:将代码分解为最小的语义化结构的片段
句法分析:分解为语法树 SST
语义分析:类型检查、类型推断、查看类型是否匹配、逃逸分析、函数调用内联
SSA代码分析
- $env:GOSSAFUNC=”main”
- go build
查看plan9 汇编代码: go build -gcflags -S main.go
空结构体
空结构体的地址均相同
空结构体主要是为了节省内存
用途: hashset、channel的类型
数据类型的长度
- 使用 unsafe.Sizeof(uint(1)) 求数据的长度
- int和指针的占用内存大小得看机器字长
nil、空接口和空结构体的区别
nil
- nil 是空,但不一定是空指针
- nil是六种类型的零值:pointer interface func channel map slice
- 虽然为nil,但每种类型的nil是不同的,无法比较
1 |
|
空接口
- 两个属性都为 nil时,该interface才为nil接口
1 |
|
空结构体
- 空结构体是Go中的非常特殊的类型
- 空结构体的值不是nil
- 空结构体也不是nil,但都是相同的(zerobase)
1 |
|
总结:
- nil是多个类型的零值,或者空值
- 空结构体的指针和零值都不是nil
- 空接口的零值是nil,一旦有了类型信息就不是nil
string
1 |
|
unicode
- 一种统一的字符集
- 其囊括了159种文字144679个字符
- 14万个字符至少需要3个字节表示
UTF-8变长编码
- Unicode的一种变长格式
- 128个US-ASCII字符只需要一个字节编码
- 西方常用字符需要两个字节
- 其他字符需要三个字节,极少数需要四个字节
其中
- 对字符串使用len得到的是字节数而不是字符数
- 字符串直接用下标访问时得到的是字节
- 字符串被range时,被解码成rune类型的字符
map
sync.Map的使用
协程
协程的抽象
- 协程的本质是一个g结构体
- gobuf表示程序运行现场
线程的抽象
- runtime中将操作系统线程抽象为m结构体
- 其中g0是操作调度器
- curg 表示目前线程运行的g
锁
atomic操作
- atomic是硬件层面加锁的机制
- 只能用于简单变量的简单操作 cas + - load
- 保证操作一个变量的时候,其他协程/线程无法访问
mutex
其中 WaiterShift表示 等待锁的协程个数
正常模式 lock
尝试使用CAS加锁
无法直接获取,进行多次自旋尝试
多次尝试失败,进入sema队列休眠
正常模式下可能会有锁饥饿问题
饥饿模式
- 当协程等待超过锁的时间超过了1ms,切换到饥饿模式
- 饥饿模式中,不自旋,新来的协程直接进入sema休眠
- 被唤醒的协程直接获取锁
锁竞争激烈时,互斥锁进入饥饿模式
·
socket连接
阻塞
非阻塞IO
多路复用epoll event-pool
重写redis组件
http://example.com/2024/01/19/重写redis组件/