这是我参与「第三届青训营 -后端场」笔记创作活动的的第2篇笔记
并发编程
并发多线程程序在一个核的CPU上运行
并行多线程程序在多个核的CPU上运行
GO语言处理并发很厉害
Goroutine
协程:用户态,轻量级线程,栈KB级别。
线程:内核态,线程跑多个协程,栈MB级别。
Goroutine支持“顺序通信进程”(communicating sequential processes)或被简称为CSP。CSP是一种现代的并发编程模型,在这种编程模型中值会在不同的运行实例(goroutine)中传递,尽管大多数情况下仍然是被限制在单一实例中。
当一个程序启动时,其主函数即在一个单独的goroutine中运行,我们叫它main goroutine。新的goroutine会用go语句来创建。在语法上,go语句是一个普通的函数或方法调用前加上关键字go。go语句会使其语句中的函数在一个新创建的goroutine中运行。而go语句本身会迅速地完成。
主函数返回时,所有的goroutine都会被直接打断,程序退出。除了从主函数退出或者直接终止程序之外,没有其它的编程方法能够让一个goroutine来打断另一个的执行。但是可以通过goroutine之间的通信来让一个goroutine请求其它的goroutine,并让被请求的goroutine自行结束执行。
CSP 顺序通信进程
提倡 通过通信共享内存 而不是 通过共享内存实现通信
Channel
channel是一种引用类型
make(chan type,[size])
根据size可选,分为有缓冲通道和无缓冲通道
无缓冲通道又被称为同步通道。
当消费者的消费速度可能慢于生产者,就要用到缓冲,这样不会影响到生产者的生产效率。
WaitGroup
使用sleep进行暴力的阻塞是不提倡的。因为不确定子协程确切的执行时间,也就无法精确地设置一个sleep的时间。
Go中使用WaitGroup进行同步。有三个方法
Add(delta int)计数器+deltaDone()计数器-1Wait()阻塞直到计数器为0
依赖管理
对于简单的单体函数,使用原生的标准库就可以完成
但对于复杂的工程项目,不可能基于标准库进行0-1的编码搭建
应该把精力放在业务逻辑上,而其他依赖,设计框架,日志等都可以通过SDK的方式引入,对依赖包的管理就比较重要。
主要管理的:
- 不同环境、项目依赖的版本不同
- 控制依赖库的版本
使用GOPATH进行依赖管理的弊端:无法实现包的多版本控制
使用GoVender的弊端:无法控制依赖的版本。更新项目可能出现依赖冲突,导致编译出错。
Go Module
通过go.mod文件管理依赖包版本
通过go get/go mod 指令工具管理以依赖包
终极目标:定义版本规则和管理项目依赖关系
依赖管理的三要素
- 配置文件,描述依赖 → go.mod
- 中心仓库管理依赖库 → Proxy
- 本地工具 → go get/mod
依赖配置 - go.mod
go.mod文件由三部分组成:
- 依赖管理基本单元:以
module开头,后面是路径 - 原生库:标识go的原生库版本号
- 单元依赖:
require开头,后面是依赖的版本号
version
go方便版本的管理,定义了自己的版本规则
语义化版本:
${MAJOR}.${MINOR}.${PATCH}
如:V1.3.0
基于commit的伪版本
vx.0.0-yyyymmddhhmmss-xxxxxxxxxxxx
版本-时间戳-哈希码
go对版本的依赖选择:选择最低的兼容版本。
关键字
indirect:标识该依赖是间接依赖
incompatible:主版本2+模块会在模块路径增加/vN后缀。对于没有go.mod文件并且主版本2+的依赖,会+该关键字
依赖分发
直接使用代码仓库的弊端:
- 无法保证构建的稳定性。可能出现增、删、改软件版本
- 无法保证依赖可用性。删除软件
- 增加第三方压力。代码托管平台负载问题
Proxy会缓存代码托管平台的软件内容。可实现稳定可靠的依赖。
变量 GOPROXY
GOPROXY=服务站点URL列表,direct
寻找依赖时会从列表中一个个寻找,找不到最终回源。
测试
测试是避免事故的最后一道屏障
单元测试
单元测试的规则
- 所有测试文件都是以_test.go结尾
func TestXxx(*testing.T)- 初始化逻辑放到TestMain中。
单元测试- 代码覆盖率
衡量代码经过了足够的测试
评价项目的测试水准
评估项目是否达到了高水准测试等级
一般覆盖率为50-60,较高的为80+
测试分支相互独立、全面覆盖。
测试单元粒度足够小,函数单一职责。
单元测试- 依赖
幂等:单元测试重复运行时结果的一致性。
稳定:单元测试能够相互隔离。任何时间,任何的测试函数能够独立运行。
Mock测试
monkey github.com/bouk/monkey
快速Mock函数:为一个函数或方法打桩
打桩:用一个函数A替换另一个函数B,B就是原函数,A就是打桩函数。
使用打桩函数替换了原函数,不再依赖本地的文件来进行测试功能函数的有效性。
基准测试
优化代码,需要对当前代码分析。内置的测试框架提供了基准测试的能力。
基准测试:测试一段程序运行时的性能和CPU的损耗。