这是我参与[第三届青训营-后端场]笔记创作活动的第9篇笔记。
一、并发VS并行
1.并发:多线程程序在一个核的CPU上运行(分时系统)
广义的并发可以为一种系统处理事务的能力
2.并行:多线程程序在多个核的CPU上运行
广义上可以理解为实现并发的一个手段
Go可以充分发挥多核优势,高效运行
1.1 Goroutine
线程:用户态,轻量级线程,栈MB级别
协程:内核态,线程跑多个协程,栈KB级别
Go语言甚至可以同时跑几万个协程(性能消耗更小,更轻便)
go语言想要起协程,只需要在想要并行执行的部分前加go,后面跟一个func函数
1.2 CSP(Communicating Sequential Process)
Go提倡通过通信共享内存而不是通过共享内存而实现通信,但也保留了右图中通过共享内存实现通信的方式。
说到直接通信,就不得不说“通道”
1.3 Channel
make(chan 元素类型,[缓冲大小])
- 无缓冲通道 make(chan int)
- 有缓冲通道 make(chan int,2) 【后面的数字意思为容量】
左图就是直接的消息提供,没有架子,直接把东西给出去;右图是有架子的,生产者将东西放到架子上,消费者从架子上取东西
1.4 并发安全 lock
声明锁的方式:lock sync.Mutex
加锁语句:lock.Lock()
释放锁语句:lock.Unlock()
1.5 WaitGroup
如果不想用sleep实现阻塞,那就要用WaitGroup。
之前只能用Sleep的原因是不知道子协程什么时候结束,那么我们用线程组的话就默认为我们统计已经完成任务的子协程:
计数器:开启协程+1;执行结束-1;主写成发阻塞直到计数器为0
使用方式:
二、依赖管理
2.1 Go依赖管理演进
依赖管理的产生原因及目的:
- 工程项目不可能基于标准库0~1编码搭建
- 管理依赖库
Go依赖管理演进:GOPATH => GO Vendor => Go Module
GoPath
环境变量$GOPATH
项目代码直接依赖src下的代码
go get 下载最新版本的包到src目录下(有点点像maven)
- 项目目录结构:
- bin(生成的二进制运行代码)
- src(所有源码,所有依赖的源码也在其中)
- pkg(编译生成的包)。
弊端:无法实现package的多版本的控制
Go Vendor
项目目录下增加vendor文件,所有依赖包副本形式放在$ProjectRoot/vendor
依赖寻址方式:vendor => GOPATH
通过每个项目引入一份依赖的副本,解决了多个项目需要同一个package依赖的冲突问题
弊端:
- 无法控制依赖的版本
- 更新项目又可能出现依赖冲突,导致编译出错。
Go Module
通过go.mod文件管理依赖包版本
通过go get/go mod指令工具管理依赖包
Go Module实现了终极目标:定义版本规则核管理项目依赖关系
2.2 依赖管理三要素
1.配置文件,描述依赖 go.mod
2.中心仓库管理依赖库 Proxy
3.本地工具 go get/mod
2.3 依赖配置
语义化版本:{MAJOR}.{MINOR}.{PATCH}
主版本2+模块会在模块路径增加/vN后缀
对于没有go.mod文件并且主版本2+的依赖,会加(说明可能会有不兼容的代码路径)
依赖配置——依赖图:选择最低的兼容版本(首先保证1.3,1.4兼容!首先要兼容,其次最低)
并且只要满足本次最低构建即可
依赖分发——回源
直接使用代码平台源头做分发:
1.无法保证构建稳定性 增加/修改/删除软件版本
2.无法保证依赖可用性 删除软件
3.增加第三方压力 代码托管平台负载问题
依赖分发——Proxy
GoProxy:
变量:GOPROXY
GORPOXY="proxy1.cn,https://proxy2.cn,…"
服务站点URL列表,"direct"表示源站
工具go get
go mod
init 初始化,创建go.mod文件
download 下载模块到本地缓存
tidy 增加所需要的依赖,删除不需要的依赖
依赖管理三要素
1.配置文件,描述依赖
2.中心仓库管理依赖库
3.使用代理拉取依赖
三、测试
回归测试:运维通过终端回归一些主流场景
集成测试:对一组相似功能进行自动化测试
单元测试:面对开发阶段,对函数的测试
单元测试的规则
1.所有测试文件以_test.go结尾
2.func TestXxx(*testing.T)
3.初始化逻辑放到TestMain中
func TestMain(m *tsting.M){
//测试前:数据装载、配置初始化
code := m.Run()
//测试后:释放资源等收尾工作
}
单元测试的运行:
运行RUN xxx(测试文件文件名)
单元测试断言
assert.Equal()
单元测试-覆盖率
1.如何衡量代码经过了足够的测试
2.如果评价项目的测试水准
3.如果评估该次项目达到了较高的测试水准
单元测试-Tips
一般覆盖率:50%~60%,较高覆盖率80%
测试分值相互独立、全面覆盖
测试单元粒度足够小,函数单一职责
单元测试-Mock
monkey: github.com/bouk/monkey
快速Mock函数:为一个函数打桩、为一个方法打桩
使测试不依赖于本地文件,任何时间任何环境都可以运行
单元测试-依赖
单元测试-文件处理
基准测试:
1.优化代码,需要对当前代码进行分析
2.内置的测试框架提供了基准测试的能力
基准测试函数开头:benchmark
FastSelect()