Go语言进阶 | 青训营笔记
01. 语言进阶
协程vs线程:
- 协程:用户态,轻量级线程,栈KB级别
- 线程:内核态,线程跑多个协程,栈MB级别
协程提倡通过通信共享内存而不是通过共享内存而实现通信
- 当然,也支持共享内存,但是需要互斥量
Channel
make(chan 元素类型, [缓冲大小])
-
无缓冲通道 make(chan int)
能实现通道连接的两个协程同步,因此也叫同步通道
-
有缓冲通道 make(chan int, 2)
可以通过协程之间的通道通信实现有序性
-
如下图例程通过A与B之间的通信实现了0~9数字的有序性
通过加锁能够实现协程安全的问题,加锁之后能够保证并发安全问题
WaitGroup
通过WaitGroup和其暴露的三个方法来实现协程的阻塞
定义:var wg sync.WaitGroup
三个方法:
- Add(delta int) 计数器+delta
- Done() 计数器-1
- Wait() 阻塞直到计数器为0
开启协程+1;执行结束-1;主协程阻塞直到计数器为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()
}
02. 依赖管理
利用其他人开发好获得验证的工具来进行开发,工程项目不可能基于标准库0~1编码搭建,因此要管理依赖库
Go依赖管理演进
三个阶段:
- GOPATH
- Go Vendor
- Go Module:广泛应用
不同环境(项目)依赖的版本不同,控制依赖库的版本
GOPATH
-
环境变量 $GOPATH
会有三个文件
. | |——bin //项目编译的二进制文件 |——pkg //项目编译的中间产物,加速编译 |——src //项目源码 -
项目代码直接依赖src下的代码
-
go get下载最新版本的包到src目录下
GOPATH弊端:在场景Project A和Project B依赖于某一package的不同版本时,无法实现package的多版本控制
Go Vendor
- 项目目录下增加vendor文件,所有依赖包副本形式放在
$ProjectRoot/vendor - 依赖寻址方式:vendor=>GOPATH
通过每个项目引入一份依赖的副本,解决了多个项目需要同一个package依赖的冲突问题
Go Vendor弊端:
- 无法控制依赖的版本
- 更新项目有可能出现依赖冲突,导致编译出错
Go Module
通过go.mod文件管理依赖包版本,通过go get/go mod指令工具管理依赖包
终极目标:定义版本规则和管理项目依赖关系
依赖管理三要素:
- 配置文件,描述依赖:
go.mod - 中心仓库管理依赖库:
Proxy - 本地工具:
go get/mod
依赖配置——go.mod
依赖配置——
version
-
语义化版本
${MAJOR}.${MINOR}.${PATCH}V1.3.0 V2.3.0
-
基于commit伪版本
vX.0.0-yyyymmddhhmmss-abcdefgh1234v.0.0.0-20220401081311-c38fd59326b7
v1.0.0-20201130134442-10cb98267c6c
依赖配置——indirect
假设有A->B->C,那么A->B是直接依赖,A->C是间接依赖
依赖配置——incompatible
- 主版本2+模块会在模块路径增加/vN后缀
- 对于没有go.mod文件并且主版本2+的依赖,会+incompatible
依赖分发——Proxy
通过在依赖存在的代码托管平台与开发者之间添加一个Proxy,能够实现稳定可靠的依赖分发的功能
依赖分发-变量——GOPROXY
GOPROXY="https://proxy1.cn, https://proxy2.cn ,direct"- 服务站点URL列表,"direct"表示源站
- Proxy 1 --> Proxy 2 --> Direct
工具——go get
工具——go mod
03. 测试
测试是避免事故的最后一道屏障
回归测试->集成测试->单元测试,覆盖率逐渐变大,成本逐渐降低
单元测试
规则:
- 所有测试文件以
_test.go结尾 - func TestXxx(*testing.T)
- 初始化逻辑放到
TestMain中
Mock测试
基准测试
- 优化代码,需要对当前代码分析
- 内置的测试框架提供了基准测试的能力