这是我参与「第五届青训营 」伴学笔记创作活动的第 2 天
Go笔记
Day_02进阶语法
语言进阶
并发VS并行
并发:多线程程序在一个核的cpu上运行
并行:多线程程序在多个核的cpu上运行
Go可以充分发挥多核优势,高效运行,为并发而生
Goroutine线程/协程
协程:用户态,轻量级线程,栈KB级别
线程:内核态,线程跑多个协程,栈MB级别
//为函数创建一个协程
go functionName(){
}
//函数名前面加一个go关键字
协程之间的通信提倡采用通信实现共享内存,使用通道进行
Channel通道
是一个引用数据类型
//定义方法
make(chan type,[缓冲大小])
//无缓冲
make(chan,int)
//有缓冲
make(chan,int,2)
并发安全Lock
示例:对变量执行2000次+1的操作,5个协程并发执行
var (
number int64
lock sync.Mutex
)
//不加锁的情况下,边界值处会有所影响,导致计算结果有误差
func numberAddOutLock() {
for i := 0; i < 2000; i++ {
number += 1
}
}
//加锁的情况下,边界值处不会有影响,计算结果精确
func numberAddLock() {
for i := 0; i < 2000; i++ {
lock.Lock()
number += 1
lock.Unlock()
}
}
//测试类
func TestNumberAdd(t *testing.T) {
number = 0
for i := 0; i < 5; i++ {
go numberAddOutLock()
}
time.Sleep(time.Second)
//没有加锁,结果不精确输出
fmt.Println("outLock:", number)
number = 0
for i := 0; i < 5; i++ {
go numberAddLock()
}
time.Sleep(time.Second)
//加了锁,结果精确输出
fmt.Println("lock:", number)
}
WaitGroup
Add:计数器+delta
Done:计数器-1
Wait:阻塞直到计数器为0
处理并发
依赖管理
GoPath
bin 编译的二进制文件
pkg 编译的中间产物
src 项目源码
无法实现多版本的pkg控制
GoVendor
无法控制依赖的版本,可能造成依赖冲突
GoModel
- 通过go.mod文件管理依赖包版本
- 通过go get/go mod指令工具管理依赖
- 定义版本规则、管理项目依赖
依赖管理三要素
- 配置文件,描述依赖 go.mod
- 中心仓库管理依赖库 Proxy
- 本地工具 go get/mod
依赖配置-version
语义化版本
{MINOR}.${PATCH}
V1.3.0
V2.3.1
基于commit伪版本
vx.0.0-yyyymmddhhmmss-abcdefgh1234
v0,0,0-202201012108-c38fb5932b7
依赖配置-indirect
非指定依赖
依赖配置-incompatible
主版本2+模块会在模块路径增加/vN后缀。 对于没有go.mod文件并且主版本2+的依赖,会+incompatibe
Go会选择最低兼容版本
依赖分发-回源
使用git去代码仓库拉去依赖
依赖分发-Proxy
如果采用默认的GOPROXY,会容易出现错误,因为默认的是国外网站,所以一般需将GOPROXY值改成国内URL
//查看go环境
go env
//修改GOPROXY的地址
go env -w GOPROXY="https://goproxy.cn"
单元测试
保证质量提高效率
- 所有测试文件以_test.go结尾
- func TestXxxx(*testing.T)
- 初始化逻辑放到TestMain中
Tips
- 一般覆盖率:50%~60%,较高覆盖率80%+
- 测试分支相互独立、全面覆盖
- 测试单元粒度足够小,函数单一职责