Go语言上手(二) | 青训营笔记

131 阅读5分钟

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

并发编程

并发多线程程序在一个核的CPU上运行

并行多线程程序在多个核的CPU上运行

GO语言处理并发很厉害

Goroutine

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

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

Goroutine支持“顺序通信进程”(communicating sequential processes)或被简称为CSP。CSP是一种现代的并发编程模型,在这种编程模型中值会在不同的运行实例(goroutine)中传递,尽管大多数情况下仍然是被限制在单一实例中。

当一个程序启动时,其主函数即在一个单独的goroutine中运行,我们叫它main goroutine。新的goroutine会用go语句来创建。在语法上,go语句是一个普通的函数或方法调用前加上关键字go。go语句会使其语句中的函数在一个新创建的goroutine中运行。而go语句本身会迅速地完成。

主函数返回时,所有的goroutine都会被直接打断,程序退出。除了从主函数退出或者直接终止程序之外,没有其它的编程方法能够让一个goroutine来打断另一个的执行。但是可以通过goroutine之间的通信来让一个goroutine请求其它的goroutine,并让被请求的goroutine自行结束执行。

CSP 顺序通信进程

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

Channel

channel是一种引用类型

make(chan type,[size])

根据size可选,分为有缓冲通道和无缓冲通道

无缓冲通道又被称为同步通道。

当消费者的消费速度可能慢于生产者,就要用到缓冲,这样不会影响到生产者的生产效率。

WaitGroup

使用sleep进行暴力的阻塞是不提倡的。因为不确定子协程确切的执行时间,也就无法精确地设置一个sleep的时间。

Go中使用WaitGroup进行同步。有三个方法

  1. Add(delta int) 计数器+delta
  2. Done() 计数器-1
  3. Wait() 阻塞直到计数器为0

依赖管理

对于简单的单体函数,使用原生的标准库就可以完成

但对于复杂的工程项目,不可能基于标准库进行0-1的编码搭建

应该把精力放在业务逻辑上,而其他依赖,设计框架,日志等都可以通过SDK的方式引入,对依赖包的管理就比较重要。

主要管理的:

  1. 不同环境、项目依赖的版本不同
  2. 控制依赖库的版本

使用GOPATH进行依赖管理的弊端:无法实现包的多版本控制

使用GoVender的弊端:无法控制依赖的版本。更新项目可能出现依赖冲突,导致编译出错。

Go Module

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

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

终极目标:定义版本规则和管理项目依赖关系

依赖管理的三要素

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

依赖配置 - go.mod

go.mod文件由三部分组成:

  1. 依赖管理基本单元:以module 开头,后面是路径
  2. 原生库:标识go的原生库版本号
  3. 单元依赖:require 开头,后面是依赖的版本号

version

go方便版本的管理,定义了自己的版本规则

语义化版本:

${MAJOR}.${MINOR}.${PATCH}

如:V1.3.0

基于commit的伪版本

vx.0.0-yyyymmddhhmmss-xxxxxxxxxxxx

版本-时间戳-哈希码

go对版本的依赖选择:选择最低的兼容版本。

关键字

indirect:标识该依赖是间接依赖

incompatible:主版本2+模块会在模块路径增加/vN后缀。对于没有go.mod文件并且主版本2+的依赖,会+该关键字

依赖分发

直接使用代码仓库的弊端:

  1. 无法保证构建的稳定性。可能出现增、删、改软件版本
  2. 无法保证依赖可用性。删除软件
  3. 增加第三方压力。代码托管平台负载问题

Proxy会缓存代码托管平台的软件内容。可实现稳定可靠的依赖。

变量 GOPROXY

GOPROXY=服务站点URL列表,direct

寻找依赖时会从列表中一个个寻找,找不到最终回源。

测试

测试是避免事故的最后一道屏障

单元测试

单元测试的规则

  1. 所有测试文件都是以_test.go结尾
  2. func TestXxx(*testing.T)
  3. 初始化逻辑放到TestMain中。

单元测试- 代码覆盖率

衡量代码经过了足够的测试

评价项目的测试水准

评估项目是否达到了高水准测试等级

一般覆盖率为50-60,较高的为80+

测试分支相互独立、全面覆盖。

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

单元测试- 依赖

幂等:单元测试重复运行时结果的一致性。

稳定:单元测试能够相互隔离。任何时间,任何的测试函数能够独立运行。

Mock测试

monkey github.com/bouk/monkey

快速Mock函数:为一个函数或方法打桩

打桩:用一个函数A替换另一个函数B,B就是原函数,A就是打桩函数。

使用打桩函数替换了原函数,不再依赖本地的文件来进行测试功能函数的有效性。

基准测试

优化代码,需要对当前代码分析。内置的测试框架提供了基准测试的能力。

基准测试:测试一段程序运行时的性能和CPU的损耗。