这是我参与「第三届青训营 -后端场」笔记创作活动的的第2篇笔记
一、语言进阶
1.并发vs并行
并发:多线程程序在单核CPU上运行,时间片轮转控制线程运行时间
并行:多线程程序在多核CPU上运行
Go可以充分发挥并行优势,是为并发而生的
2.协程vs线程
线程:内核态,比较珍贵的资源,栈KB级别
协程:用户态,轻量级线程,栈MB级别
3.开启协程:
在调用函数时,前加go即可创建协程
func hello(name string){
fmt.Println("hello "+name)
}
func main(){
go hello("Mike") //创建协程调用
hello(“Mike”) //主线程调用
}
4.协程通信——共享内存
提倡通过通信共享内存,而不是通过共享内存(需要加锁)实现通信
锁的定义如下:
//并发安全Lock
//定义内存加锁
var(
x int64
lock sync.Mutex
)
//锁的使用
func useClock(){
lock.Lock()
x += 1
lock.Unlock()
}
5.协程通信——Channel
make(chan 元素类型,[缓冲大小])
·无缓冲通道:make(chan int)
·有缓冲通道:make(chan int,2)
示例如下:
func main(){
src :=make(chan int)
dest :=make(chan int,3)
go func(){
defer close(src) //协程结束时关闭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{
fmt.Printf("%v ",i)
}
}
6.WaitGroup
由于协程运行时间不确定,暴力的使用sleep往往会增加时间开销
开启协程时+1
关闭协程时-1
主协程阻塞直到计数器为0
即等待所有并发任务完成。
| 函数 | 作用 |
|---|---|
| Add(delta int) | 计数器加delta |
| Done() | 计数器减一 |
| Wait() | 阻塞直到计数器为0 |
二、Go依赖
- GOPATH时期
项目代码直接依赖src下的代码
go get 下载最新版本的包到src目录下
弊端:无法实现package的多版本控制
- bin:项目编译产生的二进制文件
- pkg:项目编译的中间产物,加速编译
- src:项目源码
2.Go Vender时期
项目目录下增加vender文件,所有依赖包副本形式放在¥ProjectRoot/vender
依赖寻址方式:vender=>GOPATH
通过每个项目引入一个依赖的副本,解决了多个项目需要一个package的依赖冲突问题
无法控制依赖的版本
更新项目又可能出现依赖冲突导致编译出错
- README.md
- dao
- handler
- main.go
- service
- vendor
3.Go Module
通过go.mod文件管理依赖包版本
通过go get/go mod指令工具管理依赖包
4.依赖管理三要素
- go.mod 配置文件,描述依赖
- Proxy 中心仓库管理依赖库
- go get/mod 本地工具
三、Go测试
从上到下覆盖率变大,但成本降低
- 回归测试
- 集成测试
- 单元测试
规则:
- 所有测试文件以 _test.go结尾
- fun TestXxx(*testing.T)
- 初始化逻辑放到TestMain中