这是我参与「第五届青训营 」笔记创作活动的第1天
Channel
提倡通过通信实现共享内存
无缓冲通道 make(chan int)
有缓冲通道 make(chan int,2)
WaitGroup
Add(delta int) 计数器加delta
Done() 计数器-1
Wait() 阻塞直到计数器为0
使用方法:
func ManyGoWait(){
var wg sync.WaitGroup
wg.Add(5)
for i := 0; i<5; i++{
go func(j int) {
defer wg.Done()
hello(j)
}(i)
}
wg.Wait()
}
依赖管理
GOPATH
- bin 二进制文件
- pkg 项目编译的中间产物
- src 项目源码
项目代码直接依赖src下的代码
go get下载最新版本的包到src目录下
弊端:无法实现package的多版本控制
Go Vender
项目目录增加vendor文件,依赖包以副本形式放。
弊端:
- 无法控制依赖的成本
- 更新项目又可能出现依赖
Go Module
终极目标:定义版本规则和管理项目依赖关系
go.mod 配置文件, 描述依赖
Proxy 中心仓库管理依赖库
go get/mod 本地工具
//indirect 表示的是间接依赖的包
依赖分发
直接使用版本管理仓库下载依赖存在以下问题:
- 无法保证构建确定性 软件作者可以增加/修改/删除软件版本
- 无法保证以来可用性:可以直接删除软件,导致不可用
- 大幅增加第三方代码托管平台压力
Go Proxy,直接从proxy拉取依赖。
Go Proxy可以写多个,先从第一个下载,如果不存在,再往后面去找。
go get example.org/pkg
@update 默认
@none 删除依赖
@v1.1.2
@master 分支的最新commit
@23dfdd5 特定的commit
go mod init 初始化,创建go.mod文件
go mod download 下载模块到本地缓存
go mod tidy 本地工具
测试
测试是避免事故的最后一个屏障
回归测试:通过终端测试一些主流程场景
集成测试:对系统功能维度做测试验证
单元测试:测试开发阶段对单独函数进行测试
成本从上倒下降低,覆盖率增加
单元测试
单元测试可以保证质量、提升效率
-
所有测试以_test.go结尾
-
assert包
func TestHelloTom(t *testing.T) { output := HelloTom() expectOutput := "Tom" assert.Equal(t, expectOutput, output) }
覆盖率:测试的行数占总代码行数的百分比,100%的时候对所有代码是有信心的,主流程的覆盖率一般要求50%-60%
Mock测试
如果读取文件进行测试的话,测试结果会对文件有依赖,可以对读文件函数进行mock,屏蔽对文件的依赖。
使用Monkey开源mock测试库,可以将内存中的函数地址替换为运行时函数地址。
func TestProcessingFirstLineWithMock(t *testing.T) {
monkey.Patch(ReadFirstLine, func() string {
return "line110"
})
defer monkey.Unpatch(ReadFirstLine)
line := ProcessFirstLine()
assert.Equal(t, "line000", line)
}
基准测试
基准测试(benchmarking)是一种测量和评估软件性能指标的活动。你可以在某个时候通过基准测试建立一个已知的性能水平(称为基准线),当系统的软硬件环境发生变化之后再进行一次基准测试以确定那些变化对性能的影响。