Go语言快速上手(四) | 青训营笔记

129 阅读4分钟

这是我参与[第三届青训营-后端场]笔记创作活动的第9篇笔记。

一、并发VS并行

1.并发:多线程程序在一个核的CPU上运行(分时系统)

广义的并发可以为一种系统处理事务的能力

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

广义上可以理解为实现并发的一个手段

Go可以充分发挥多核优势,高效运行

1.1 Goroutine

线程:用户态,轻量级线程,栈MB级别

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

Go语言甚至可以同时跑几万个协程(性能消耗更小,更轻便)

go语言想要起协程,只需要在想要并行执行的部分前加go,后面跟一个func函数

1.2 CSP(Communicating Sequential Process)

image.png

Go提倡通过通信共享内存而不是通过共享内存而实现通信,但也保留了右图中通过共享内存实现通信的方式。

说到直接通信,就不得不说“通道”

1.3 Channel

make(chan 元素类型,[缓冲大小])

  • 无缓冲通道 make(chan int)
  • 有缓冲通道 make(chan int,2) 【后面的数字意思为容量】

image.png 左图就是直接的消息提供,没有架子,直接把东西给出去;右图是有架子的,生产者将东西放到架子上,消费者从架子上取东西

1.4 并发安全 lock

声明锁的方式:lock sync.Mutex

加锁语句:lock.Lock()

释放锁语句:lock.Unlock()

1.5 WaitGroup

如果不想用sleep实现阻塞,那就要用WaitGroup。

之前只能用Sleep的原因是不知道子协程什么时候结束,那么我们用线程组的话就默认为我们统计已经完成任务的子协程: image.png 计数器:开启协程+1;执行结束-1;主写成发阻塞直到计数器为0

使用方式: image.png

二、依赖管理

2.1 Go依赖管理演进

依赖管理的产生原因及目的:

  • 工程项目不可能基于标准库0~1编码搭建
  • 管理依赖库

Go依赖管理演进:GOPATH => GO Vendor => Go Module

GoPath

环境变量$GOPATH

项目代码直接依赖src下的代码

go get 下载最新版本的包到src目录下(有点点像maven)

  • 项目目录结构:
  • bin(生成的二进制运行代码)
  • src(所有源码,所有依赖的源码也在其中)
  • pkg(编译生成的包)。

弊端:无法实现package的多版本的控制

Go Vendor

项目目录下增加vendor文件,所有依赖包副本形式放在$ProjectRoot/vendor

依赖寻址方式:vendor => GOPATH

通过每个项目引入一份依赖的副本,解决了多个项目需要同一个package依赖的冲突问题

弊端:

  • 无法控制依赖的版本
  • 更新项目又可能出现依赖冲突,导致编译出错。
Go Module

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

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

Go Module实现了终极目标:定义版本规则核管理项目依赖关系

2.2 依赖管理三要素

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

2.中心仓库管理依赖库 Proxy

3.本地工具 go get/mod

2.3 依赖配置

语义化版本:{MAJOR}.{MINOR}.{PATCH} image.png image.png image.png image.png

主版本2+模块会在模块路径增加/vN后缀

对于没有go.mod文件并且主版本2+的依赖,会加(说明可能会有不兼容的代码路径) image.png

依赖配置——依赖图:选择最低的兼容版本(首先保证1.3,1.4兼容!首先要兼容,其次最低)

并且只要满足本次最低构建即可

依赖分发——回源

直接使用代码平台源头做分发:

1.无法保证构建稳定性 增加/修改/删除软件版本

2.无法保证依赖可用性 删除软件

3.增加第三方压力 代码托管平台负载问题

依赖分发——Proxy

GoProxy:

image.png

变量:GOPROXY

GORPOXY="proxy1.cn,https://proxy2.cn,…"

服务站点URL列表,"direct"表示源站

工具go get

image.png

go mod

init 初始化,创建go.mod文件

download 下载模块到本地缓存

tidy 增加所需要的依赖,删除不需要的依赖

依赖管理三要素

1.配置文件,描述依赖

2.中心仓库管理依赖库

3.使用代理拉取依赖

三、测试

image.png

回归测试:运维通过终端回归一些主流场景

集成测试:对一组相似功能进行自动化测试

单元测试:面对开发阶段,对函数的测试

image.png

单元测试的规则

1.所有测试文件以_test.go结尾

2.func TestXxx(*testing.T)

3.初始化逻辑放到TestMain中

func TestMain(m *tsting.M){

//测试前:数据装载、配置初始化

code := m.Run()

//测试后:释放资源等收尾工作

}

单元测试的运行:

image.png

运行RUN xxx(测试文件文件名)

单元测试断言

image.png

assert.Equal()

单元测试-覆盖率

1.如何衡量代码经过了足够的测试

2.如果评价项目的测试水准

3.如果评估该次项目达到了较高的测试水准

单元测试-Tips

一般覆盖率:50%~60%,较高覆盖率80%

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

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

单元测试-Mock

monkey: github.com/bouk/monkey

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

使测试不依赖于本地文件,任何时间任何环境都可以运行

单元测试-依赖

image.png

单元测试-文件处理

image.png

基准测试:

1.优化代码,需要对当前代码进行分析

2.内置的测试框架提供了基准测试的能力

基准测试函数开头:benchmark

FastSelect()

image.png image.png image.png