day2笔记整理简洁版:)
go语言进阶和依赖管理
协程
并发:多线程在一个核的cpu上运行 并行:多线程在多个核的cpu上运行
Goroutine(协程)
- 线程:内核态,(昂贵的系统资源)线程跑多个协程,MB级别
- 协程:用户态,轻量级线程,KB级别
使用协程:在函数前加上go/协程通信CSP
- 不推荐借助临界区(共享内存)实现通信
- 推荐使用通信(通道)来共享内存
Channel(通道)
Make(chan 元素内心 int)
- 无缓冲通道 make (chan int)//同步通道
- 有缓冲通道 make (chan int,2)//缓冲区大小为2
由于消费者的逻辑可能比生产者复杂,因此在消费者和最终结果之间加上有缓冲的通道,防止其对生产者效率的影响
并发安全Lock(共享内存实现通信)
- WaitGroup:(代替sleep进行阻塞)实现并发任务的同步(计数器)
- Add(delta int)//调用多少个并发任务
- Done()//计数器-1
- Wait()//阻塞,等待所有并发任务执行结束
依赖管理
不同环境依赖的版本不同
GOPATH(环境变量)
- Bin//项目编译的二进制文件
- Pkg//中间产物
- Src//源码
项目直接依赖src的代码,Go get下载最新版本的包(无法实现多版本控制,只能有一个版本的package)
Go Vendor
项目目录增加一个vendor文件,依赖包副本存放在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.16
require (
github.com/gin-contrib/sse v0.1.0 // indirect
github.com/gin-gonic/gin v1.3.0 // indirect
github.com/go-playground/validator/v10 v10.10.0 // indirect
github.com/goccy/go-json v0.9.6 // indirect
github.com/golang/protobuf v1.5.2 // indirect
github.com/jinzhu/now v1.1.5 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/kr/pretty v0.3.0 // indirect
github.com/mattn/go-isatty v0.0.14 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/rogpeppe/go-internal v1.8.0 // indirect
)
- 模块路径(依赖管理基本单元)
- 原生库版本号
- 单元依赖
Version(版本规则)
语义化版本
- ${MAJOR}大版本,代码隔离可以不兼容
- ${MINOR}小版本,前后兼容,包括新增函数和功能。
- ${PATCH}版本修复
基于commit伪版本
版本前缀-时间戳-哈希码前缀
Indirect关键字
没有直接导入的模块为间接依赖,用indirect标识出来
Incompatible
对于v2以上的依赖,在版本号的后面做标识,当选择多个版本时,选择最低的兼容版本
依赖分发
Proxy
- 缓存软件内容(稳定,可靠)
GOPROXY(url列表)=“proxy1,proxy2,direct”
测试
单元测试
单元测试规则
- 测试文件以_test.go结尾
- Func TestXxx(testing.T)
- 初始化逻辑放到TestMain(测试前进行数据装载、配置初始化等前置工作)//测试后进行资源释放等收尾工作
断言:assert
评估测试: 代码覆盖率
Go --cover计算覆盖率
如何提高?
- 测试分支相互独立、全面覆盖
- 测试单元粒度足够小,函数单一职责
- 依赖(幂等、稳定)(文件可能被篡改或删除,则该函数无法运行)
- 幂等:重复做一次case的结果相同
- 稳定:单元测试相互隔离
Mock(运行时,将内存中函数地址进行替换)
为一个函数打桩/为一个方法打桩
- Patch(target//目标函数,replacement//打桩函数)//用打桩函数替换目标函数
- Unpatch//卸载桩
Mockey的作用是原函数由于调用第三方的内容无法执行时,进行打桩将其替代来测试其他函数的功能。
基准测试(对代码进行性能分析)
Rand的性能在并行时变低(全局锁) Fastrand
项目实践
社区话题页面
- 展示话题(标题,文字描述)和回帖列表
- 暂不考虑前端页面实现,仅仅实现一个本地web服务
- 话题和回帖数据用文件存储
步骤
- 定义需求用例
- ER图
- 分层结构
- 数据层:数据model。外部数据的增删改查
- 逻辑层:业务Entity,处理核心业务逻辑输出
- 视图层:视图view,处理和外部的交互逻辑
组件工具:
1.Gin高性能go web框架 2.Go Mod
Repsository:
实现基本查询操作: QueryTopicById QueryPostsByParentId
借助index索引map快速定位到数据,定义两个map来查找.
- 打开文件
- 将数据行遍历
- 转换为结构体并存储到map中
查询操作:直接给根据id在map中寻找
Service层
定义实体:
type PageInfo struct {
Topic *repository.Topic
PostList []*repository.Post
}
PrepareInfo:从Repsository层拿数据(借用两个查询方法)
两者没有相互依赖,可以进行并行.
Controller层
- 构建view对象
- 业务错误码
Router
- 初始化数据索引
- 初始化引擎配置
- 构建路由
- 启动服务