Go工程基础课程笔记| 青训营笔记

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

零、简介

本文根据字节跳动后端青训营第二节课 GO语言入门-工程实践 撰写,是本人记录的一些偏分散的知识点,阅读前请注意时效性,仅供参考。


一、语言进阶

1、并发VS并行

二者都是指多线程程序在CPU上运行,不同点在于并发是指多线程程序在一个核的CPU上运行,并行是指多线程程序在多个核的CPU上运行。 并行可以充分发挥多核优势,高效运行。

2、Goroutine

协程:用户态,轻量级,栈MB级别。 线程:内核态,线程跑多个协程,栈KB级别。

创建goroutine的方式:在函数前加上“go”

go func(j int) {
	...
}(j)

3、CSP

CSP全称 Communicating Sequential Process 提倡通过通信共享内存而不是通过共享内存而实现通信,需要对临界区加锁实现。


4、Channel

channel就是通信的通道 创建方式如下:

chan := make(chan type, [size])

其中type表示通道的元素类型,size表示通道的缓冲大小,无缓冲通道则不需要设置缓冲大小

往channel中输入数据如下:

chan <- val

channel遍历操作如下:

for i := range chan {
	...
}

消费者处理速度比生产者慢时,带缓冲通道可避免影响生产者的运行效率。


5、并发安全与Lock锁

Lock用于处理临界区资源 创建方式:

var {
	name type
	...
	lock sync.Mutex
}

其中name为需要加锁的变量名称,type为对应的变量类型

上锁与解锁:

lock.Lock()
...
lock.Unlock()

6、WaitGroup

实现并发任务的同步,内含计数器 创建方法:

var wg sync.WaitGroup

使用方法:

wg.Add(delta int) //计数器+delta
wg.Done()         //计数器-1
//在协程中开头添加defer wg.Done()
Wait()         //主协程阻塞,直到计数器为0为止

二、依赖管理

1、GOPATH

该目录三个主要文件夹

bin 项目编译的二进制文件 pkg 项目编译的中间产物,加速编译 src 项目源码

项目代码直接依赖 src 下的代码 go get 下载最新版本的包到 src 目录下

弊端

无法实现不同项目依赖同package的多版本控制。


2、GOVENDER

项目目录下添加Vender文件夹,存放依赖包副本,依赖寻址方式:vender -> GOPATH 解决了上文提到的依赖冲突问题。

弊端

无法实现不同子项目依赖同package的多版本控制。实际上依赖的是源码而不是版本。


3、GOMODULE

官方的依赖管理系统 通过go.mod文件管理依赖包版本 通过go get / go.mod 指令工具管理依赖包

3.1、管理依赖三要素

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

3.2、依赖配置

gomod文件:
module example/project/app //依赖管理基本单元 如:github.com/...

go 1.16 //原生库

require ( //单元依赖
	example/lib1 v1.0.2 
	example/lib2 v1.0.4 //indrect 
	example/lib3 v1.0.6+incompatible
	...
)
version

语义化版本: V{MAJOR}.{MINOR}.{PATCH} 如:V1.1.2 基于commit伪版本 vX.0.0-yyyymmddmmss(commit时间戳)-aaaabbbbcccc(hash)

indirect

如:A->B->C

  • A->B 直接依赖
  • A->C 简介依赖
incompatible

对于没有 go.mod文件且主版本2+的依赖的兼容标志

3.3、依赖分发GOPROXY

保证构建稳定,可用,解决代码托管平台负载问题

3.4、工具

go get

命令格式:

go get example.org/pkg ...

"...":

@update //默认
@none //删除依赖
@v1.1.2 //tag语义版本
@(hash) //特定的commit
@master //分支最新的commit
go mod

命令格式:

go mod ...

"...":

init //初始化,创建go.mod文件
download //下载模块到本地缓存
tidy //增加需要依赖,删除多余依赖

三、测试

1、单元测试

对测试单元输入数据,再将其实际输出与期望输出做对比进行校对的过程。单元可以是函数,模块等等。

  • 所有测试文件以 *_test.go 结尾
  • 测试函数命名为TestXxx(t *testing.T)
  • 初始化逻辑放到TestMain(m *testing.M)中
func TestMain(m *testing.M) {
	//数据装载
	code := m.Run()
	//释放资源
	os.Eixt(code)
}

覆盖率

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


2、Mock

对单元打桩测试,由特定函数产生输入,不依赖本地文件。


3、基准测试

  • 优化代码,需要对当前代码分析
  • 内置的测试框架提供了基准测试的能力
  • 以Benchmark开头的函数
  • ResetTimer()重置计时