这是我参与「第三届青训营 -后端场」笔记创作活动的的第2篇笔记
并发编程
- 并发VS并行
- 并发:多线程程序在一个核的cpu上运行
- 并行:多线程程序在一个核的cpu上运行 Go可以充分发挥多核优势,高效运行
- Goroutine
- 协程:用户态,轻量级线程,栈MB级别
- 线程:线程跑多个协程,栈KB级别
go 函数(函数参数)
//快速打印hello goroutine: 0~4
func hello(i int){
println("hello goroutine:"+fmt.Sprint(i))
}
func main(){
for i:=0;i<5;i++{
go func(j int){
hello(j)
}(i)
}
}
- CSP(Communicating Sequential Processes)
- 提倡通过通信共享内存而不是通过共享内存实现通信
- Channel
make(chan 元素类型[,缓冲大小])
- 无缓冲通道
make(chan int) - 有缓冲通道
make(chan int,2)
func CalSquare() {
src := make(chan int)
dest := make(chan int, 3)
go func() {
defer close(src)
for i := 0; i < 10; i++ {
src <- i
}
}()
go func() {
defer close(dest)
for i := range src {
dest <- i * i
}
}()
for i := range dest {
println(i)
}
}
5.并发安全Look
- 使用sync中的lock(),unlock()实现
var(
x int64
lock sync
)
func addWithLock() {
for i:= 0; i<2000; i++{
lock.Lock()
x+=1;
lock.Unlock()
}
}
- WaitGroup
- Add(delta int) 计数器+delta
- Done() 计数器-1
- Wait()阻塞直到计数器为0
func main(){
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()
}
依赖管理
- 背景
- 工程项目不可能基于标准库0~1编码构建
- 管理依赖库
- Go依赖管理演进
- GOPATH -> GO Vendor -> Go Module
- GOPATH
- 环境变量$GOPATH
- 项目代码直接依赖src下的代码
- go get 下载最新版本的包到src目录下
弊端:无法实现package的多版本控制
- Go Vender
- 项目目录下增加vendor文件,所有依赖包副本形式放在$ProjectRoot/vendor
- 依赖寻址方式:vendor -> GOPATH
弊端: 无法控制依赖的版本
更新项目又可能出现依赖冲突,导致编译出错
- Go Module
- 通过go.mod文件管理依赖包版本
- 通过go get/go mod指令工具管理依赖包
- 依赖管理三要素
- 配置文件,描述依赖 go mod
- 中心仓库管理依赖库 Proxy
- 本地工具 go get/mod
测试
回归测试 集成测试 单元测试
- 从左到右 覆盖率变大,成本变低
1.单元测试
- 保证质量
- 提升效率
规则
- 所有测试文件以_test.go结尾
- func TestXxx(t *tasting.T)
- 初始化逻辑放到TestMain中
覆盖率
go test xxx_test.go --cover
依赖
- 外部依赖 -> 稳定&幂等
- Mock测试
快速Mock函数
- 为一个函数打桩
- 为一个方法打桩
- 基准测试
- 优化代码,需要对当前代码分析
- 内置的测试框架提供了基准测试的能力