这是我参与「第三届青训营-后端场」笔记创作活动的的第2篇笔记。
并发编程
并发:多线程程序在单核cpu上运行。广义上代表了一种对外的能力。
并行:多线程程序在多核cpu上运行,可以视作实现并发的一种手段。
Go实现了高效的调度模型实现高并发的操作。
- 协程:用户态、轻量级线程,栈KB级别。线程:内核态,可以运行多个协程,栈MB级别。
- Go 语言中的协程(goroutine),通过
go关键字。 - 推荐使用通信共享内存(通道)而不是共享内存(临界区)实现通信。
- Channel
make(chan int, 2)- 无缓冲通道。同步通道。
- 有缓冲通道。生产-消费模型。
- sync.WaitGroup. 主要包含三个方法:
Add(n),Done():计数器-1,Wait():阻塞至计数器为0。 - sync.Mutex. 互斥锁。
依赖管理
- GOPATH. 直接依赖$GOPATH/src下的代码。无法实现package多版本控制。
- Go Vendor. 每个项目引入一份依赖的副本$ProjectRoot/vendor。
- Go Module. 通过
go.mod文件管理依赖包版本,通过go get/go mod管理依赖包。- 配置文件
go.mod。非直接依赖有//indirect标注,对于非直接依赖的不同版本,Go会选择一个最低兼容版本。 - 中心仓库。Proxy
- 本地工具。
go get example.org/pkg@update|none|...默认下载最新版本。go mod init|download|tidy创建go.mod文件;下载到本地缓存;下载所需,删除多余。
- 配置文件
- version
- 语义化版本 {minor}.${patch}。major-大版本,互相可以不兼容;minor-新增功能,做到前后兼容;patch-bug修复。
- 基于 commit vx.0.0-yyyymmddhhmmss-abcdefgh1234。版本前缀-时间戳-哈希码。
- 依赖分发。不直接以来第三方代码平台,使用Proxy作为中间缓存。
GOPROXY="https://proxy1.cn, https://proxy2.cn, direct"
单元测试
回归测试,集成测试,单元测试。覆盖率依次变大,成本依次降低。
- 测试文件
_test.go结尾。 - 函数
func TestXxx(*testing.T)。 - 初始化逻辑放在
TestMain()中。 - 单元测试的代码覆盖率。通过
go test --cover选项,对测试过程中代码执行的比例进行统计。一般覆盖率50%~60%,较高覆盖率80%+。- 测试分支相互独立,不重不漏;
- 测试单元粒度足够小,函数单一职责;
- Mock测试。为了实现单元测试的幂等,稳定要求,可以使用Mock(打桩)取消一些依赖。以monkey为函数打桩为例:
Patch(target, replacement)Unpatch(target)卸载桩
- 基准测试。主要用于优化代码的效率。
- 测试函数
BenchmarkXxx(b *testing.B)或BechmarkXxxParallel(b *testing.B) b.ResetTimer()b.RunParallel(func(pb *testing.PB) {})并行运行
- 测试函数
项目实战:社区话题页面
实现一个展示话题和回帖列表的后端http接口。实现要点包括:
- 使用Gin框架
- 本地文件存储
- 分层结构设计
- Repository. 主要负责:
- 构建索引。由数据行建立内存map
- 查询。
- Service. 主要负责:
- 参数校验(id)
- 准备数据(topic,post)。可以使用goroutine并行处理
- 组装实体
- Controller. 主要负责:
- 构建View对象
- 业务错误处理
- Router. 主要负责
- 初始化数据索引
- 初始化引擎配置
- 构建路由
- 启动服务
- Repository. 主要负责: