这是我参与「第五届青训营 」伴学笔记创作活动的第 2 天
本堂课的重点内容
今日课程的主要内容包括并发编程、依赖管理、测试、项目实战等内容。
课程具体内容
并发编程
这里涉及了很多概念。go中的并发似乎都是通过协程而非线程来解决的(不知道目前这样理解对不对)
并发与并行
并发:多线程在单核上运行 并行:多线程在多核上运行
线程与协程
- 协程:用户态,可以理解为轻量级的线程。栈KB级别。
- 线程:内核态,栈MB级别
主要包括Goroutine、Channel等。 go中提倡通过通信来共享内存。因此需要使用通道。通过通道可以连接多个协程。
go创建 Channel的方式:
src := make(chan int)//没有缓冲通道的
dest := make(chan int, 3)//有缓冲通道,其大小为3
src <- i//代表将i放入src中
为了并发时的安全,go中使用的是Lock。首先要创建lock,用完后要释放lock。其他语言中也有类似的东西。
func addWithLock() {
for i := 0; i < 2000; i++ {
lock.Lock()
x += 1
lock.Unlock()
}
}
依赖管理
依赖的演进路线
主要是GOPATH、Go Vendor、Go Module。
GOPATH
是一个go项目的工作区。其下面主要有bin、pkg和src三个目录。bin下放的是编译后的二进制文件,pkg放置用于加速编译的中间产物(很好奇具体是哪些东西),src放源码。 弊端:无法实现package的多版本控制。
Go Vendor
在项目目录下会增加一个名字为vendor的文件夹。依赖会优先在vendor中找,找不到才从path中找。 弊端:无法控制依赖的版本(想想就觉得糟糕)
Go Module
为了解决Go Vendor的问题,出现了Go Module。 通过go.mod文件管理依赖包的版本,通过go get/go mod指令工具管理依赖包。
可以看出都是为了解决之前方案存在的问题,才进而提出了新的方案。
依赖管理的三要素
需要描述文件(如go.mod)描述依赖了哪些库,需要中心仓库(Proxy)和本地工具(如go get/mod)
go.mod的文件结构
module github.com/Moonlight-Zhao/go-project-example //依赖管理的基本单元
go 1.19 //go的原生库(版本相关)
require ( //具体依赖了哪些库以及版本
bou.ke/monkey v1.0.2
github.com/bytedance/gopkg v0.0.0-20220401081311-c38fb59326b7
github.com/stretchr/testify v1.7.1
gopkg.in/gin-gonic/gin.v1 v1.3.0
github.com/davecgh/go-spew v1.1.1 // indirect
)
指定版本有两种方式:一种语义化版本(Vxxx的形式),另一种是基于伪commit的形式(vxx.xx-xxxxxx-xxxx这样的格式) indirect关键字的含义是非直接依赖。比如说A依赖B,B依赖C,那么A就是不直接依赖B。
分发变量-GOPROXY。其配置的格式为:GOPROXY=https://proxy1.cn,https://proxy2.cn,direct。"direct"表示直接从源站下载依赖。
顺便感谢这节课,刚开始用goland发现死活下不了依赖,一直报错。然后看了分发变量这里的内容后,我将GOPROXY改成七牛云的就能正常下来依赖了。配置如下:GOPROXY=https://goproxy.cn,direct。
测试
可以分为三种类型,分别是:回归测试、集成测试、单元测试。从上到下,覆盖率逐渐增大,成本逐渐降低。
- 回归测试
- 集成测试
- 单元测试 单元测试的组成:包括输入、测试单元、输出以及与期望的校对。此处的单元包括函数、接口等。
单元测试的规则
-
所有的测试文件以_test.go结尾。这样就可以清晰地区分源代码和测试代码。
-
函数名称的格式:func TestXxx( * testing.T)。 如想要测试函数
CalSquare(),那么测试函数应写为func TestCalSquare( * testing.T) -
初始化逻辑要放在TestMain中。
评估单元测试
代码覆盖率
一般覆盖率在50%~60%,较高会到80%。 提高覆盖率的方法: 测试分支要相互独立。 测试单元的粒度要足够小,函数单一职责。
依赖
需要幂等和稳定。幂等:重复运行case时运行结果一样。稳定:单元测试相互隔离。
Mock测试
用一个函数B去替换函数A。这里我暂时还没理解,先mark住吧,以后慢慢实战多了应该就懂了。
基准测试
测试运行一段程序时的性能以及CPU的损耗。其使用方法类似单元测试。 其测试文件要求形如``` func BenchmarkXxx(b *testing.B)
如```
func BenchmarkSelect(b *testing.B)
项目实践
一个项目的开发过程包括需求分析、代码开发、测试运行这三个步骤。 在需求分析阶段需要指明项目的要求与目的、项目结构等内容。通常分为数据层、逻辑层、视图层。数据层就是实现对外部数据的增删改查等操作,逻辑层处理业务的核心逻辑,视图层处理与外部的交互问题,如转json等。
总结
今日主要学习了go的进阶知识,包括在go中如何进行并发、如何导入go中的第三方库、如何进行测试,并通过一个项目加深理解。这节课好多不太熟的概念,比如mock测试、基准测试,之前接触的不多,只有慢慢学习了。