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

105 阅读3分钟

Go 语言上手 - 工程实践、

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


语言进阶

并发VS并行

并发:主要是多线程程序在单核CPU上通过时间片切换达到同时运行的状态。

并行:主要是使用多核CPU实现多线程同时运行的状态。

Goroutine

协程:用户态,轻量级线程,栈KB级别。

线程:内核态,线程跑多个协程,栈MB级别。

go开启协程运行函数。

CSP(Communicating Sequential Processes)

Go提倡通过通信来共享内存

Channel

make创建channel,可以有缓冲。

无缓冲通道也就是同步通道。

缓冲满了会阻塞发送。

带缓冲的channel可以解决生产消费效率不同的问题。

并发安全Lock

sync.Mutex锁。

Lock()加锁。

Unlock()解锁。

WaitGroup

sync.WaitGroup通过计数器等待。

Add()计数器加多少。

Done()计数器减1。

Wait()等待到计数器为0。

依赖管理

目标

  • 实现不同环境(项目)依赖的版本不同。
  • 控制依赖库的版本。

Go Module

通过go.mod文件管理依赖包版本。

通过go get/mod指令工具管理依赖包。

依赖管理三要素

  • 配置文件,描述依赖 go.mod
  • 中心仓库管理依赖库 Proxy
  • 本地工具 go get/mod

go.mod

module标识模块。

go原生库

require单元依赖。

依赖标识:[Module Path][Version/Pseudo-version]

version

语义化版本V[Major].[Minor].[Patch]

基于commit伪版本[语义化版本]-yyyymmddhhmmss-abcdefgh1234

indirect

表明不是直接导入的依赖,是间接依赖。

incompatible

主版本2+模块会在模块路径增加/vN后缀。

没有go.mod文件且主版本2+的依赖,会+incompatible,表示可能不兼容。

依赖图

Minor版本一般都是向下兼容的。

Go会选择最低的兼容版本。

依赖分发

Proxy站点缓存依赖代码,直接从Proxy拉取依赖。

通过GOPROXY变量配置服务站点URL列表。

按配置顺序查找。

go get

go get example.org/pkg后面加

  • @update 默认
  • @none 删除依赖
  • @[version] tag版本,语义版本
  • @[commit提交] 特定的commit
  • @[分支] 分支的最新commit

go mod

go mod后面加

  • init 初始化,创建go.mod文件
  • download 下载模块到本地缓存
  • tidy 增加需要的依赖,删除不需要的依赖

测试

回归测试

正常使用场景测试。

集成测试

对系统功能自动化测试。

单元测试

开发者对函数模块做测试验证。

通过输入输出与期望输出的校对来测试代码的正确性。

测试单元粒度足够小,函数单一职责。

单元测试-规则

  • 所有测试文件以_test.go结尾
  • func TestXxx(*testing.T)
  • 初始化逻辑放到TestMain

assert

通过断言校对。

代码覆盖率

go test [测试文件] [代码文件] --cover输出覆盖率。

Mock

  • 幂等 多次运行单元测试结果是一样的。
  • 稳定 单元测试是相互隔离的,任何时间任何地点都能独立运行。

Patch为函数打桩,在测试时调用打桩函数。

Unpatch卸载。

基准测试

基准测试以Benchmark开头。

BenchmarkXxx(*testing.B)

InitServerIndex()开始。

ResetTimer()重置计时。

RunParallel()并行执行。

fastrand牺牲一些随机数列一致性,提升高并发速度。

项目实践

分层结构

  • 数据层Repository:外部数据的增删改查。
  • 逻辑层Service:处理核心业务逻辑输出。
  • 视图层Controller:处理和外部的交互逻辑。

组件工具

  • Gin go web框架

索引

数据行 -> 内存Map

通过将数据存到内存map内实现索引。

查询

sync.Once高并发场景中只执行一次,类似单例模式。

Router

  • 初始化数据索引
  • 初始化引擎配置
  • 构建路由
  • 启动服务