Go语言入门——工程实践 7.26
1.语言进阶
1.1 Go routine
快速打印hello goroutine : 0~ hello goroutine : 4
1.2 CSP
CSP(Communicating Sequential Processes)
提倡通过通信共享内存而不是通过共享内存而实现通信
1.3 Channel
make(chan元素类型,[缓冲大小])
- 无缓冲通道 make(chan int)
- 有缓冲通道 make(chan int,2)
A子协程发送0~9数字
B子协程计算输入数字的平方
主协程输出最后的平方数
1.4 并发安全lock
对变量执行2000次+1操作,5个协程并发执行
1.5 WaitGroup
计数器
开启协程+1;执行结束-1;主协程阻塞直到计数器为0。
快速打印 hello goroutine : 0~hello goroutine : 4
2.依赖管理
2.1 依赖管理演进
- 不同环境(项目)依赖的版本不同
- 控制依赖库的版本
2.1.1 GOPATH
环境变量 $GOPATH
项目代码直接依赖 src 下的代码
go get下载最新版本的包到 src 目录下
弊端
场景:A和B依赖于某一 package的不同版本
问题:无法实现package的多版本控制
2.1.2 Go Vender
- 项目目录下增加 vendor 文件,所有依赖包副本形式放在 $ProjectRoot/vendor
- 依赖寻址方式::vendor => GOPATH
通过每个项目引入一份依赖的副本,解决了多个项目需要同一个 package 依赖的冲突问题。
弊端
问题
- 无法控制依赖的版本。
- 更新项目又可能出现依赖冲突,导致编译出错。
2.1.3 Go Module
- 通过go.mod文件管理依赖包版本
- 通过go get/go mod指令工具管理依赖包
终极目标:定义版本规则和管理项目依赖关系
2.2 依赖管理三要素
- 配置文件,描述依赖 go.mod
- 中心仓库管理依赖库 Proxy
- 本地工具 go get/mod
2.3 依赖管理
2.3.1 依赖配置-go.mod
依赖标识:[Module Path] [Version / Pseudo-version]
2.3.2 依赖配置-version
- 语义化版本
${MAJOR}.${MINOR}.${PATCH}
V1.3.0
V2.3.0
- 基于commit伪版本
vx.0.0-yyymmddhhmmss -abcdefgh1234
v0.0.0- 20220401081311-c38fb59326b7
v1.0.0- 20201130134442-10cb98267c6c
2.3.3 依赖配置-indirect
A->B->C
A->B 直接依赖
A->C 间接依赖
2.3.4 依赖配置-incompatible
- 主版本2+模块会在模块路径增加/vN后缀。
- 对于没有go.mod文件并且主版本2+的依赖,会+incompatible
依赖图
如果X项目依赖了A、B两个项目,且A、B分别依赖了C项目的v1.3、v1.4两个版本,最终编译时所使用的C项目的版本为如下哪个选项?(单选)
A. v1.3
B. v1.4
C. A用到C时用v1. 3编译, B用到C时用v1.4编译
选择 B,选择最低的兼容版本
2.3.5 依赖分发
回源
- 无法保证构建稳定性 增加/修改/删除软件版本
- 无法保证依赖可用性 删除软件
- 增加第三方压力 代码托管平台负载问题
Proxy
2.3.6 依赖分发-变量GOPROXY
GOPROXY = “proxy1.cn, proxy2.cn ,direct” 服务站点URL列表,“direct” 表示源站
Proxy1—> Proxy2—> Direct
2.3.7 工具-go get
go get example.org/ pkg
@update 默认
@none 删除依赖
@v1.1.2 tag版本,语义版本
@23dfdd5 特定的commit
@master 分支的最新commit
2.3.8 工具-go mod
go mod
init 初始化,创建go.mod文件
download 下载模块到本地缓存
tidy 增加需要的依赖,删除不需要的依赖
3.测试
测试是避免事故的最后一道屏障
从上到下,覆盖率逐层变大,成本却逐层降低
3.1 单元测试
3.1.1 单元测试-规则
- 所有测试文件以test.go 结尾
- func TestXxx(*testing.T)
- 初始化逻辑放到TestMain中
3.1.2 单元测试-例子
3.1.3 单元测试-运行
go test [flags][packages]3.1.4 单元测试-assert
3.1.5 单元测试-覆盖率
如何衡量代码是否经过了足够的测试?
如何评价项目的测试水准?
如何评估项目是否达到了高水准测试等级?
代码覆盖率
测试1
测试2
Tips:
- 一般覆盖率: 50%~ 60%, 较高覆盖率80%+。
- 测试分支相互独立、全面覆盖。
- 测试单元粒度足够小,函数单一职责。
3.2 单元测试-依赖
外部依赖 => 稳定&幂等
3.3 单元测试-文件处理
3.4 单元测试-Mock
快速Mock函数
- 为一个函数打桩
- 为一个方法打桩
对ReadFirstLine打桩测试,不再依赖本地文件
3.5 基准测试
- 优化代码,需要对当前代码分析
- 内置的测试框架提供了基准测试的能力
3.5.1 基准测试-例子
随机选择执行服务器
3.5.2 基准测试-运行
3.5.3 基准测试-优化
4.项目实践
4.1 需求描述
社区话题页面
- 展示话题(标题,文字描述)和回帖列表
- 暂不考虑前端页面实现,仅仅实现一个本地web服务
- 话题和回帖数据用文件存储
4.2 需求用例
浏览消费用户
4.3 ER图
Entity Relationship Diagram
话题 帖子
4.4 分层结构
数据层:数据Model,外部数据的增删改查
逻辑层:业务Entity,处理核心业务逻辑输出
视图层:视图view,处理和外部的交互逻辑
4.5 组件工具
- Gin高性能go web框架
https:// github.com/ gin-gonic/ gin#installation
- Go Mod
go mod init
go get gopkg.in/gin-gonic/gin.v1@v1.3.0
4.6 Repository
Topic
QueryTopicByld
Post
QueryPostsByParentId
如何实现查询
Index
初始化题数据索引
查询
索引:话题ID
数据:话题
索引:话题ID
数据:帖子列表
4.7 Service
实体
流程
代码流程编排
可用性
并行处理
4.8 Controller
构建View对象
业务错误码
4.9 Router
初始化数据索引
初始化引擎配置
构建路由
启动服务
4.10 运行
运行测试
go run server.go