这是我参与「第五届青训营 」伴学笔记创作活动的第2天
01 并发
协程( Goroutine)
用户态,轻量级,栈内存小。并发利器
- 通过通信共享内存(通道实现)而不是共享内存而实现通信(临界区),Go保留了两种方式。
通道
引用类型
- 无缓冲通道
make(chan int)
,也称同步通道。发送的goroutine和接收的goroutine同步化。 - 有缓冲通道
make(chan int,2)
典型的生产消费模型。
func callSquare(){
src := make(chan int)
dest := make(chan int, 3)
// A子协程发送0~9数字
go func(){
defer close(src)
for i:=0;i<10;i++{
src<-i
}
}()
// B子协程计算输入数字的平方
go func(){
defer close(dest)
for i := range src{
dest<-i*i
}
}()
for i:=range dest{
// 主协程输出最后的平方数。
// 复杂操作。消费者消费速度比生产者速度慢,所以使用带缓冲区的channel
fmt.Println(i)
}
}
- 临界区实现并发
- sync包下,实现并发任务同步。
暴露三个方法Add、Done、Wait,内部是维护一个计数器。
02 依赖管理
依赖:各种开发包
背景
第三方依赖通过sdk方式引入
Go 依赖管理研究
Go PATH->Go Vendor->Go Module(当前广泛应用)
- Go PATH
弊端:无法实现依赖包的多版本控制
- Go Vendor
增加了vendor文件夹;解决了多个项目需要同一个依赖包的冲突问题。
Go Module实践
- Go Module
终极目标:定义版本规则和管理项目依赖关系
Go1.16版本默认开启
-
- 通过go.mod 文件管理依赖包版本
- 通过go get/go mod 指令工具管理依赖包
依赖管理三要素
-
- 配置文件,描述依赖 go.mod
- 中心仓库管理依赖 Proxy
- 本地工具 go get/mod
- 依赖配置
-
- indirect 在go mod没有直接导入的间接依赖
- incompatible 主版本2+模块会在路径增加/vN后缀;对于没有go.mod文件并且主版本2+的依赖,会+incompatible
- 依赖图
选B,原则选择最低的兼容版本。
- 依赖分发
依赖去哪里下载
- proxy
缓存了依赖的不同版本
go proxy解决了
先去proxy1下载依赖,如果不存在去go proxy2,如果还不在就去源仓库下载。这种设计了类似缓存,如果缓存中不存在数据,就去DB读数据。
- 本地工具
每次提交代码前执行一次go tidy
03 单元测试
测试是避免事故的最后一道屏障
回归测试:点点点
集成测试:功能维度
单元测试:开发阶段,对开发功能的验证x 。
单元测试
- 代码覆盖率
如何衡量代码是否已经经过了足够吧的测试?
如何评价项目的测试水准?
如何评估项目是否达到了高水准测试等级?
评估上述问题
整个函数,前两行代码被验证过,最后一行没验证过。所以覆盖率是:2/3=66.7%
Tips:
- 一般的覆盖率:50%~60%。较高覆盖率80%+。
- 测试分支相互独立、全面覆盖。
- 测试单元粒度足够小,函数单一职责。
Mock测试
target是目标待测函数。repalcement是打桩函数
基准测试
- 优化代码,需要对当前代码分析(测试一段程序CPU的性能)
- 内置的测试框架提供了基础测试的能力