这是我参与「第五届青训营 」伴学笔记创作活动的第 2 天
Go语言进阶与依赖管理
语言进阶
并发和并行
Go可以发挥多核优势,高效运行
协程和线程
协程:用户态,轻量级线程,栈KB级别
线程:内核态,线程可以并发多个协程,栈MB级别
创建协程
在函数调用的前面,加上 go关键字,即可创建协程
CSP (Communicating Sequential Processes)
这是协程之间的通信
Go语言提倡通过通信共享内存,而不是通过共享内存而实现通信
一般而言,通过共享内存而实现通信的性能较前者弱
Channel
这是一个引用类型,需要使用make关键字创建
包括有缓和无缓通道两类
Lock 并发安全
尽量避免对于共享内存进行读写操作
WaitGroup
与 Lock 一样处于 sync 包下
实现并发任务的同步
Go依赖管理
控制依赖库的管理
Go PATH
弊端 当两个项目依赖某一package的不同版本,无发实现package的多版本控制
Go Vendor
通过每个项目引入一份依赖的副本,解决了多个项目需要同一个package的问题 但是
可能导致编译错误
Go Module
通过 go.mod 文件管理依赖包版本 通过 go get/go mod指令工具管理依赖包 可以实现 定义版本规则和管理依赖关系 依赖管理
三要素
1. 配置文件 go mod
2. 中心仓库管理依赖库 Proxy
3. 本地工具 go get/mod
类似于Maven
依赖版本
${MAJOR}.${MINOR}.${PATCH}
MAJOR: 是大版本,各个大版本之间可以不兼容
MINOR: 一般是新增函数和功能
PATCH: 代码bug的修复
Go语言工程实践之测试
单元测试
规范
- 所有测试文件以
_test.go结尾 - 所有测试函数以
func TestXxx (*testing.T)命名 - 初始化逻辑放到
func TestMain(m *testing.M)中
覆盖率
Command
go test执行测试--cover返回覆盖率
Tips
- 一般覆盖率:50%~60%;较高覆盖率:80%+
- 测试分支相互独立、全面覆盖
- 测试单元粒度足够小,函数单一职责
Mock测试
外部依赖
外部依赖 => 稳定&幂等
幂等 => 多次测试结果相同
打桩
monkey:github.com/bouk/monkey
进行打桩替换,进而实现不依赖本地文件
基准测试
功能
- 优化代码,需要对当前代码分析
使用
-
Go语言内置测试框架,提供了基准测试的能力
- 用以测试程序性能
-
函数名以
Benchmark开头 -
入参
*testing.B
举例
rand函数
// 随机选择服务器
import (
"math/rand"
)
var ServerIndex [10]int
func InitServerIndex() {
for i := 0; i < 10; i++ {
ServerIndex[i] = i + 100
}
}
func Select() int {
return ServerIndex[rand.Intn(10)]
}
假设我们有10个服务器列表,每次随机选择一个执行
通过测试,我们发现多协程并发测试比穿行测试慢
原因是rand函数为了保证并发安全性和全局随机性,持有一把全局锁
字节为了解决这一随机的性能问题,开源了高性能随机数方法 fastrand
性能提升非常大
思路是牺牲了一定的数列随机性
项目实战
需求分析
需求描述
- 做一个论坛模块
- 展示话题和回帖列表
- 仅实现本地 web 服务
- 话题和回帖用文件的形式存储
ER 图 - Entity Relationship Diagram
Topic
- ID
- Title
- Content
- Poster
- CreateTime
PostList
- ID
- TopicID
- Content
- Poster
- CreateTime
二者之间是一对多的关系
分层结构
不一定要套用
组件工具
- Gin 高性能 go web 框架
- Go mod
个人想法
我之前学 Java 使用 Springboot 框架的时候从来没有考虑过为什么要分 Map, Service, Controller,只知道它们分别负责什么,而从来没有考虑过这么做的好处或者是有没有可能可以针对项目进行优化,分层结构相关的内容给了我一些启发:比如动态的数据库连接是不是可以在逻辑层和数据层中间加一层从而实现呢?