这是我参与「第五届青训营 」伴学笔记创作活动的第 2 天。主要学习了Go的并发编程、依赖管理和测试。并发编程主要包括了goroutine、channel、lock、WaitGroup 的使用。依赖管理包括GOPATH、Go Vender、Go Module。测试包括单元测试、Mock测试、基准测试。
1.并发编程
(1)goroutine
Go语言内置了调度和上下文切换的机制。在Go语言并发编程中,只需要把一个任务包装成一个函数,开启一个goroutine去执行这个函数就可以了
Go语言在main函数中会启动一个主线程,一个Go语言线程上可以起多个协程,协程是轻量级的线程
Go语言协程特点:
- 有独立的栈空间
- 共享程序堆空间
- 调度由用户控制
- 协程是轻量级的线程
使用goroutine非常简单,只需要在调用函数的时候在前面加上go关键字,就可以为一个函数创建一个goroutine
func main() {
for i := 0; i < 5; i++ {
//启动一个协程去完成打印
go func(j int) {
hello(j)
}(i)
}
time.Sleep(time.Second)
}
在程序启动时,Go程序就会为main()函数创建一个默认的goroutine。
当main()函数返回的时候该goroutine就结束了,所有在main()函数中启动的goroutine会一同结束.因此,这里为了让循环里面的goroutine执行完成,使用time.Sleep()暂停等待。
(2) channel
Go语言的并发模型是CSP(Communicating Sequential Processes),提倡通过通信共享内存而不是通过共享内存而实现通信。channel的主要作用就是实现goroutine之间的通信
Go 语言中的通道(channel)是一种特殊的类型。通道像一个传送带或者队列,总是遵循先入先出(First In First Out)的规则,保证收发数据的顺序。每一个通道都是一个具体类型的导管,也就是声明channel的时候需要为其指定元素类型。
通道是引用类型,通道类型的空值是nil。声明的通道后需要使用make函数初始化之后才能使用。创建channel的格式如下:
make(chan 元素类型, [缓冲大小])
通道有发送(send)、接收(receive)和关闭(close)三种操作。发送和接收都使用<-符号。下面是一个使用通道进行发送和接收的例子。
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)
}
}
本例中使用了一个无缓冲的channel和一个有缓存的channel。
无缓冲的channel只有在有对象接收值的时候才能发送值,使用无缓冲通道进行通信将导致发送和接收的goroutine同步化。因此,无缓冲通道也被称为同步通道。
有缓冲的channel利用缓冲区可以解决生产、消费速度不匹配的问题。
(3) 互斥锁lock
var (
x int64
lock sync.Mutex
)
func addWithLock() {
for i := 0; i < 2000; i++ {
lock.Lock()
x += 1
lock.Unlock()
}
}
不加锁会出现并发安全问题,出现未预料的结果
(4) WaitGroup 计数器
实现并发任务同步 主要方法为Add,Done,Wait
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()
}
2.依赖管理
开发项目时引入的各种开发包
(1) GOPATH->Go Vender ->Go Module
(2) GOPATH 环境变量
依赖src下的代码,通过go get下载到src目录
问题:无法实现package的多版本控制
(3) Go Vender
在项目中添加vender的依赖副本
问题:A依赖B和C,B和C的依赖冲突
无法控制依赖版本,更新可能出现依赖冲突,发生编译错误
(4) Go Module
通过go.mod管理依赖包版本
go get/go mod 管理依赖包
终极目标:定义版本规则和管理项目依赖关系
依赖管理三要素 配置文件描述依赖 go.mod 中心仓库 Proxy 本地工具 go get/mod
依赖冲突解决: 选择最低的依赖兼容版本
3.测试
单元测试 覆盖率
Mock 打桩测试 去除对于文件、数据的强依赖
基准测试 Benchmark开头 测试性能,具体花费时间