Go语言进阶与依赖管理|青训营笔记
这是我参与「第五届青训营 」伴学笔记创作活动的第 2 天
1. 并发编程
1.1 并发和并行
并发:多线程程序在一个核的cpu上通过时间片的形式同时运行
并行:多线程程序在多个核的cpu上运行
1.2 协程Goroutine和线程
协程:轻量级,用户态的,栈在mb级别
线程:切换等操作很慢,内核态,栈在kb级别
1.3 通信与通道chan
提倡通过通信共享内存(临界区),而不是通过共享内存而实现通信(MPI?)
通道chan:make(chan 元素类型,[缓冲大小])
根据是否指定缓冲大小,可以分为无缓冲通道和有缓冲通道,缓冲的应用场景就是消费者的消费速度较慢的情况
1.4 并发锁Lock
用来保证共享内存的并发安全
lock sync.Mutex:创建互斥量
lock.Lock():申请互斥量
lock.Unlock():释放互斥量
1.5 WaitGroup
wg sync.WaitGroup:类似于维护了一个有锁的计数器
Add(delta int):主协程中调用,创建子协程计数器
Done():子协程中调用,表示该子协程结束,计数器减1
Wait():主协程阻塞直到计数器为0
2. 依赖管理
核心是控制不同环境下依赖库的版本
2.1 依赖演进
gopath
$GOPATH ->bin src pkg 项目代码直接依赖src下的代码
go get:下载最新版本的包到src目录下
问题:无法实现package的多版本控制
go vendor
在项目根目录下放置 vendor 文件夹,优先查找依赖
问题:不同文件夹(package)的依赖冲突
go module 依赖管理三要素
go.mod:配置文件,描述依赖
Proxy:中心仓库管理依赖库
go get/mod:本地工具
2.2 go.mod
每个package下一般来说都需要
module example/project/app #模块路径,用于标识模块
go 1.16 #原生库版本号
require (
example/lib1(模块路径) v1.0.2(版本号)
example/lib2 v1.0.0
)
语义话版本version:${MAJOR}.${MINOR}.${PATCH}
基于commit位版本:vx.0.0-yyyymmddhhmmss-abcdefgh1234最后一部分是一个12位的哈希码前缀
//indirect关键字,间接依赖
+incompatiable:主版本2+模块会在模块路径增加/vN后缀,对于没有go.mod文件的package且主版本2+,会增加该标签,表示可能不兼容的代码
2.3 依赖分发-回源 Proxy
依赖分发的一种方式:直接从代码托管软件github等下载
问题:无法保证构建稳定性,无法保证依赖可用性,增加代码托管平台的压力
Proxy:会缓存代码托管平台中的依赖,从而保证稳定性和可靠性
环境变量GOPROXY="https://proxy1.cn, https://proxy2.cn, direct"
按照优先级从前到后排列代理站点名称,最后direct表示原代码托管平台
2.4 go get
go get example.org/pkg:默认拉取最新版本
@update:默认
@none:删除依赖
@vx.0.0:tag版本,语义版本
@23dfdd5:特定的commit
@master:特定的分支的最新commit
2.5 go mod
go mod
init:创建 go.mod文件
download:下载依赖到本地缓存
tidy:增加需要的依赖,去除不需要的依赖
3. 测试
测试分类:回归测试(最后应用),集成测试(功能),单元测试(函数模块)
单元测试:输入,输出与期望校对
3.1 单元测试规则
- 所有测试文件以
_test.go结尾 - 测试函数的命名
func TestXxx(t *testing.T) - 初始化逻辑放到
func TestMain(m *testing.M)函数中
t.Errorf
github.com/stretchr/testify/assert
assert.Equal(t, expectOutput, output)
go test judgment_test.go judgment.go --cover:可以返回单元测试的语句覆盖率
测试单元粒度足够小和函数的单一职责要求是相对应的
3.2 单元测试-依赖
稳定=幂等:每次运行的结果是一样的 Mock