这是我参与「第三届青训营 -后端场」笔记创作活动的的第4篇笔记
第二节课-GO工程实践
-
语言进阶
并发编程角度
并发VS并行
- 并发:多线程程序在一个核的cpu上运行
- 并行:多线程程序在多个核的cpu上运行
==GO可以充分发挥多核优势,高效运行。==
-
Goroutine
-
协程:用户态,轻量级线程,栈MB级别
-
线程:内核态,线程跑多个协程,栈KB级别
-
用法:
go func(j int){ //your code }(j)
-
-
CSP(Communicating Sequential Processes)
提倡通过==通信共享内存==而不是通过共享内存而实现通信。
-
Channel
make(chan 元素类型,[缓存大小])- 无缓冲通道
make(chan int) - 有缓存通道
make(chan int,size) - 发送
ch<-i - 接收
i<-ch
- 无缓冲通道
-
并发安全Lock
- 声明
var mutex sync.Mutex - 加锁
mutex.Lock() - 解锁
mutex.Unlock()
- 声明
-
WaitGroup
-
声明
var waitGroup sync.WaitGroup -
计数器+delta
waitGroup.Add(delta) -
计数器-1
waitGroup.Done() -
阻塞直到计数器为0
waitGroup.Wait() -
使用例子:
- 开启协程+1
- 执行结束-1
- 主协程阻塞直到计数器为0.
-
-
小结
主要通过Goroutine, Channel, Sync实现
-
依赖管理
-
依赖管理演进
GOPATH=>Go Vendor=>Go Module
-
GOPATH
- 目录包含bin,pkg,src三个子目录
- 项目代码直接依赖src下的代码
- go get下载最新版本的包到src目录下
- 问题:在A和B两个不同项目依赖于某个package的不同版本时无法实现package的多版本控制
-
Go Vendor
- 项目目录增加vendor文件,所有依赖包副本形式放在
$ProjectRoot/vendor - 依赖寻址方式:vendor =>GOPATH
- 解决了GOPATH中的冲突问题
- 问题:项目A依赖Package B和Package C时,若B和C依赖于Package D的不同版本D-v1, D-v2时则无法解决冲突
- 问题原因:仍然是依赖于包的源码而不能标识依赖的不同版本
- 项目目录增加vendor文件,所有依赖包副本形式放在
-
Go Module
-
特点
- 通过
go.mod文件管理依赖包版本 - 通过
go get/go mod指令工具管理依赖包 - 目标:定义版本规则和管理项目依赖关系
- 通过
-
依赖管理三要素
- 配置文件,描述依赖
go.mod - 中心仓库管理依赖库 Proxy
- 本地工具
go get/mod - 依赖标识:[Module Path][Version/Pseudo-version]
- 配置文件,描述依赖
-
version
-
语义化版本
{MINOR}.${PATCH}
- v1.3.0
- v2.3.0
-
基于commit伪版本
vX.0.0-yyyymmddhhmmss-abcdefgh1234
- v0.0.0-20220401081311-c38fb59326b7
- ...
==依赖包版本选择最低的兼容版本==
-
-
-
依赖分发
-
回源
- 无法保证构建稳定性
- 无法保证依赖可用性
- 增加第三方压力
-
Proxy
- 稳定,可靠
-
变量GOPROXY
GOPROXY=”proxy1.cn,https://proxy2.cn,…"
服务站点URL列表,“direct"标识源站
==proxy1=>proxy2=>direct==
-
-
工具
-
go get
go get example.org/pkg- @update 默认
- @none 删除依赖
- @v1.1.2 tag版本,语义版本
- @23dfdd5特定的commit
- @master分支的最新commit
-
go mod
- init 初始化,创建go.mod文件
- download下载模块到本地缓存
- tidy增加需要的依赖,删除不需要的依赖
-
-
-
测试
-
单元测试
-
测试输出与期望输出校对
-
规则
- 所有测试文件以
_test.go结尾 func TestXxx(t *testing.T){//your code}- 初始化逻辑放到
TestMain()中
- 所有测试文件以
-
运行
go test [flags][packages] -
assert
-
测试Tips
- 覆盖率需50%~60%,热点代码需80%
- 测试分支相互独立、全面覆盖
- 测试单元力度足够小,函数单一职责
-
-
Mock测试
外部依赖=>稳定&幂等
-
快速Mock函数
- 为一个函数打桩
- 为一个方法打桩
-
基准测试
- 优化代码,需要对当前代码分析
- 内置的测试框架提供了基准测试的能力
func BenchXxx(b *testing.B){//your code}b.ResetTimer(),b.RunParallel(func(pb *testing.PB){//your code})
-
-
项目实战
-
需求分析
-
需求用例
-
ER图
-
MVC分层结构
-
web框架:Gin
- 初始化数据
- 初始化引擎配置
- 构建路由
- 启动服务
-