Go语言进阶与依赖管理|青训营笔记

73 阅读3分钟

Go语言进阶与依赖管理|青训营笔记

这是我参与「第五届青训营 」伴学笔记创作活动的第 2 天

1. 并发编程

1.1 并发和并行

并发:多线程程序在一个核的cpu上通过时间片的形式同时运行

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

1.2 协程Goroutine和线程

协程:轻量级,用户态的,栈在mb级别

线程:切换等操作很慢,内核态,栈在kb级别

1.3 通信与通道chan

提倡通过通信共享内存(临界区),而不是通过共享内存而实现通信(MPI?)

通道chanmake(chan 元素类型,[缓冲大小])

根据是否指定缓冲大小,可以分为无缓冲通道和有缓冲通道,缓冲的应用场景就是消费者的消费速度较慢的情况

1.4 并发锁Lock

用来保证共享内存的并发安全

lock sync.Mutex:创建互斥量

lock.Lock():申请互斥量

lock.Unlock():释放互斥量

1.5 WaitGroup

wg sync.WaitGroup:类似于维护了一个有锁的计数器

Add(delta int):主协程中调用,创建子协程计数器

Done():子协程中调用,表示该子协程结束,计数器减1

Wait():主协程阻塞直到计数器为0

2. 依赖管理

核心是控制不同环境下依赖库的版本

2.1 依赖演进

gopath

$GOPATH ->bin src pkg 项目代码直接依赖src下的代码

go get:下载最新版本的包到src目录下

问题:无法实现package的多版本控制

go vendor

在项目根目录下放置 vendor 文件夹,优先查找依赖

问题:不同文件夹(package)的依赖冲突

go module 依赖管理三要素

go.mod:配置文件,描述依赖

Proxy:中心仓库管理依赖库

go get/mod:本地工具

2.2 go.mod

每个package下一般来说都需要

 module example/project/app #模块路径,用于标识模块 
 ​
 go 1.16 #原生库版本号
 ​
 require (
   example/lib1(模块路径) v1.0.2(版本号)
   example/lib2 v1.0.0 
 )

语义话版本version:${MAJOR}.${MINOR}.${PATCH}

基于commit位版本:vx.0.0-yyyymmddhhmmss-abcdefgh1234最后一部分是一个12位的哈希码前缀

//indirect关键字,间接依赖

+incompatiable:主版本2+模块会在模块路径增加/vN后缀,对于没有go.mod文件的package且主版本2+,会增加该标签,表示可能不兼容的代码

2.3 依赖分发-回源 Proxy

依赖分发的一种方式:直接从代码托管软件github等下载

问题:无法保证构建稳定性,无法保证依赖可用性,增加代码托管平台的压力

Proxy:会缓存代码托管平台中的依赖,从而保证稳定性和可靠性

环境变量GOPROXY="https://proxy1.cn, https://proxy2.cn, direct"

按照优先级从前到后排列代理站点名称,最后direct表示原代码托管平台

2.4 go get

go get example.org/pkg:默认拉取最新版本

@update:默认

@none:删除依赖

@vx.0.0:tag版本,语义版本

@23dfdd5:特定的commit

@master:特定的分支的最新commit

2.5 go mod

go mod

init:创建 go.mod文件

download:下载依赖到本地缓存

tidy:增加需要的依赖,去除不需要的依赖

3. 测试

测试分类:回归测试(最后应用),集成测试(功能),单元测试(函数模块)

单元测试:输入,输出与期望校对

3.1 单元测试规则

  • 所有测试文件以 _test.go结尾
  • 测试函数的命名 func TestXxx(t *testing.T)
  • 初始化逻辑放到 func TestMain(m *testing.M) 函数中

t.Errorf

github.com/stretchr/testify/assert

assert.Equal(t, expectOutput, output)

go test judgment_test.go judgment.go --cover:可以返回单元测试的语句覆盖率

测试单元粒度足够小和函数的单一职责要求是相对应的

3.2 单元测试-依赖

稳定=幂等:每次运行的结果是一样的 Mock