这是我参与「第五届青训营 」笔记创作活动的第2天
一、本堂课重点内容:
- Go语言进阶
- Go语言依赖管理
- Go语言测试
二、详细知识点介绍:
GO进阶
并行与并发
- 并行:多线程程序在一个核的cpu上运行
- 并发:多线程程序在多个核的cpu上运行
协程与进程
- 协程:用户态,轻量级线程,栈MB级别。
- 线程:内核态,线程并发跑多个协程,栈KB级别。
go语言一次可以创建上万的协程,这也是go语言更适合高并发场景的原因。
协程间的通信
go提倡通过通信共享内存,而不是通过共享内存而实现通讯。
go也保留了过共享内存而实现通讯,但这需要一些互斥量去进行加锁,限制临界区的权限,这会在一定程度上影响程序的性能。
go使用了channel来进行通信 。
Channel
channel是一种引用类型,需要使用make进行创建。
make(chan元素类型,[缓冲大小])
- 无缓冲通道
make(chan int) - 有缓冲通道
make(chan int, 2)
并发安全
主要是对共享内存的不安全操作所引起的,因为这是一个未定义的行为。例如
所以需要我们对临界资源进行控制,来并发安全的共享内存。
阻塞
上面的代码是用sleep来暴力阻塞,事实上更优雅的方式是使用计数器。
开启协程时计数器+1,执行结束时-1,主协程阻寒直到计数器为0,表明所有的并发任务都已完成。
依赖管理
GOPATH
GOPATH是go的系统变量,即go项目的工作区。
其中有以下三个关键文件
- bin 项目编译的二进制文件
- pkg 项目编译的中间产物,加速编译
- src 项目源码
项目代码直接依赖src下的代码。
go get会下载最新版本的包到src目录下。
弊端:可能有多个项目依赖于同一个包的不同版本,所以GOPATH无法实现package的多版本控制。
GO Vendor
- 项目目录下增加vendor文件,所有依赖包副本形式放在$ProjectRoot/vendor
- 依赖寻址方式:vendor=>GOPATH
通过每个项目引入一份依赖的副本,解决了多个项目需要同一个package依赖的冲突问题。
弊端:
- 无法控制依赖的版本。
- 更新项目又可能出现依赖冲突,导致编译出错。
Go Module
- 通过go.mod文件管理依赖包版本
- 通过go get/go mod 指令工具管理依赖包
- 终极目标:定义版本规则和管理项目依赖关系
- 配置文件,描述依赖 go.mod
- 中心仓库管理依赖库 Proxy
- 本地工具 go get/mod
配置-go.mod
version
语义化版本
$(MAJOR).$(MINOR).$(PATCH)
例如 V1.3.0 V2.3.0
基于commit伪版本 vX.0.0-yyyymmddhhmmss-abcdefgh1234
时间戳yyyymmddhhmmss也就是提交Commit的时间,最后是校验码(abcdefabcdef),包含12位的哈希前缀;每次提交commit后Go都会默认生成一个伪版本号。
例如
v0.0.0-20220401081311-c38fb59326b7 v1.0.0-20201130134442-10cb98267c6c
仓库-proxy
Go Proxy是一个服务站点, 它会缓源站中的软件内容,缓存的软件版本不会改变 并且在源站软件删除之后依然可用,从而实现了供"immutability"和"available“的依赖分
工具-go mod
- init 初始化,创建go.mod文件
- download 下载模块到本地缓存
- tidy 增加需要的依赖,删除不需要的依赖
测试
单元测试
单元测试主要包括输入,测试单元,输出,以及校对,单元的概念比较广,包括接口,函数,模块等
单元测试能保证质量和提升效率。
规则
- 所有测试文件以_test.go结尾
- func TestXxx(*testing.T)
- 初始化逻辑放到TestMain中
覆盖率
即实际测试运行过的代码占比。
- 一般覆盖率:50%~60%,较高覆盖率80%+。
- 测试分支相互独立、全面覆盖。
- 测试单元粒度足够小,函数单一职责。
依赖
单元测试对依赖有两个目标,一个是幂等(重复运行测试的结果是一样的),另一个是稳定(单元测试能在任何时间任何函数运行)。
Mock
如果一个测试是通过本地文件数据进行,那么这个测试便是依赖于本地文件,当这个文件被删除或者异常,就可能发生意外。
Monkey是一个用于Mock的package,通过Monkey进行打桩测试,可以不在依赖本地文件。
社区话题页面:
需求
- 展示话题(标题,文字描述)和回帖列表
- 暂不考虑前端页面实现,仅仅实现一个本地web服务
- 话题和回帖数据用文件存储
分析
E_R图
分层结构
- 数据层:数据Model,外部数据的增删改查
- 逻辑层:业务Entity, 处理核心业务逻辑输出
- 视图层:视图View,处理和外部的交互逻辑