Skip to content

Go Note

1. Go 语言进阶

1.1 并发 & 并行

  • 协程:用户态,轻量级线程,栈 KB 级别
  • 线程:内核态,线程跑多个协程,栈 MB 级别

1.2 协程间通信 CSP(Communicating Sequential Processes)

提倡通过通信共享内存而不是通过共享内存而实现通信。

1.3 Channel

make(chan 元素类型, [缓冲大小])
  • 无缓冲通道:make(chan int),同步通道
  • 有缓冲通道:make(chan int, 2),生产消费模型

1.4 并发安全 Lock

通过共享内存实现通信时,需要加锁以保证并发安全。

1.5 WaitGroup

计数器,开启协程 +1,执行结束 -1,主协程阻塞直到计数器为0。

2. 依赖管理

参考:Go mod包依赖管理工具使用详解

2.1 依赖管理演进

GOPATH -> Go Vendor -> Go Module

  • GOPATH:无法实现 package 的多版本控制
  • Go Vendor:
    • 通过每个项目引入一份依赖的副本,解决了多个项目需要同一个 package 依赖的冲突问题
    • 无法控制依赖的版本
  • Go Module:
    • 通过 go.mod 文件管理依赖包版本
    • 通过 go get/go mod 指令工具管理依赖包

2.2 依赖管理三要素

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

2.3 依赖配置 - Version

  • 语义化版本
    • ${MAJOR}.${MINOR}.${PATCH}
  • 基于 commit 伪版本
  • 版本选择:选择最低的兼容版本

2.4 依赖分发 - 回源

  • 无法保证构建稳定性
  • 无法保证依赖可用性
  • 增加第三方压力

2.5 依赖分发 - Proxy

Go Mod 通过 GOPROXY 环境变量控制 Proxy,最后会 fallback 到源站中。

2.6 工具

  • go get
  • go mod
    • init
    • download
    • tidy

3. 测试

3.1 单元测试

规则

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

覆盖率

go test judgment_test.go --cover

外部依赖

外部依赖需要稳定 & 幂等,因此需要 Mock 外部依赖。

3.2 Mock 测试

Mock 工具:Monkey

3.3 基准测试

  • func BenchmarkXxx(b *testing.B)
  • go tes -bench=.

4. 性能优化建议

  1. 使用 Benchmark 衡量性能表现;
  2. Slice:
    1. 预分配内存;
    2. 陷阱:大内存未释放
      1. 场景:原 Slice 较大,代码在原 Slice 基础上新建小切片,导致原 Slice 在内存中有引用,得不到释放
      2. 解决方案:使用 copy 代替 re-slice
  3. Map 预分配内存;
  4. 使用 string.Builder 处理字符串,而不是 + 拼接;
  5. 使用空结构体节省内存:空结构体实例不占据任何内存空间,可作为占位符使用
    1. 场景:实现 set 时可以用 map 代替,此时只需要用到 key,可以把 value 设置为空结构体
  6. 使用 atomic 包;

5. 性能调优实战

5.1 性能分析工具 pprof