Go 语言工程实践 | 青训营笔记

133 阅读3分钟

这是我参与「第三届青训营-后端场」笔记创作活动的的第2篇笔记。

并发编程

并发:多线程程序在单核cpu上运行。广义上代表了一种对外的能力。

并行:多线程程序在多核cpu上运行,可以视作实现并发的一种手段。

Go实现了高效的调度模型实现高并发的操作。

  1. 协程:用户态、轻量级线程,栈KB级别。线程:内核态,可以运行多个协程,栈MB级别。
  2. Go 语言中的协程(goroutine),通过go关键字。
  3. 推荐使用通信共享内存(通道)而不是共享内存(临界区)实现通信。
  4. Channel make(chan int, 2)
    • 无缓冲通道。同步通道。
    • 有缓冲通道。生产-消费模型。
  5. sync.WaitGroup. 主要包含三个方法:Add(n),Done():计数器-1, Wait():阻塞至计数器为0。
  6. sync.Mutex. 互斥锁。

依赖管理

  1. GOPATH. 直接依赖$GOPATH/src下的代码。无法实现package多版本控制。
  2. Go Vendor. 每个项目引入一份依赖的副本$ProjectRoot/vendor。
  3. 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文件;下载到本地缓存;下载所需,删除多余。
  4. version
    • 语义化版本 major.{major}.{minor}.${patch}。major-大版本,互相可以不兼容;minor-新增功能,做到前后兼容;patch-bug修复。
    • 基于 commit vx.0.0-yyyymmddhhmmss-abcdefgh1234。版本前缀-时间戳-哈希码。
  5. 依赖分发。不直接以来第三方代码平台,使用Proxy作为中间缓存。
    GOPROXY="https://proxy1.cn, https://proxy2.cn, direct"
    

单元测试

回归测试,集成测试,单元测试。覆盖率依次变大,成本依次降低。

  1. 测试文件_test.go结尾。
  2. 函数 func TestXxx(*testing.T)
  3. 初始化逻辑放在TestMain()中。
  4. 单元测试的代码覆盖率。通过go test --cover选项,对测试过程中代码执行的比例进行统计。一般覆盖率50%~60%,较高覆盖率80%+。
    • 测试分支相互独立,不重不漏;
    • 测试单元粒度足够小,函数单一职责;
  5. Mock测试。为了实现单元测试的幂等,稳定要求,可以使用Mock(打桩)取消一些依赖。以monkey为函数打桩为例:
    • Patch(target, replacement)
    • Unpatch(target) 卸载桩
  6. 基准测试。主要用于优化代码的效率。
    • 测试函数BenchmarkXxx(b *testing.B)BechmarkXxxParallel(b *testing.B)
    • b.ResetTimer()
    • b.RunParallel(func(pb *testing.PB) {}) 并行运行

项目实战:社区话题页面

实现一个展示话题和回帖列表的后端http接口。实现要点包括:

  1. 使用Gin框架
  2. 本地文件存储
  3. 分层结构设计
    • Repository. 主要负责:
      • 构建索引。由数据行建立内存map
      • 查询。
    • Service. 主要负责:
      • 参数校验(id)
      • 准备数据(topic,post)。可以使用goroutine并行处理
      • 组装实体
    • Controller. 主要负责:
      • 构建View对象
      • 业务错误处理
    • Router. 主要负责
      • 初始化数据索引
      • 初始化引擎配置
      • 构建路由
      • 启动服务