第二节课
1. 并发和并行
并发:一个盒时间切片 并发:多个盒运行不同 go语言为并发而生
1.1 携程
重要概念:携程
携程:用户态 轻量级线程 栈KB级别 线程:内核态 线程跑多个携程 栈MB级别。创建切换停止都是比较重的系统操作
1.2 通信
重要概念:携程之间的通信 CSP (Communicating Sequential Processes) go提倡通过通信共享内存(第一种)
共享内存:通过互斥量实现内存加速,一定程度上会出现数据静态?的问题,影响程序性能
1.3 Chanel
make(chan元素类型, [缓冲大小])
无缓冲会让发送和接收的gorountine同步化
1.4 并发安全 block
1.5 wait group
维护了一个计数器。
- 启动n个并发任务,那+n
- 每完成一个任务,就-1
- wait到所有并发任务完成
总结
- goroutine:携程高并发
- channel:通信实现共享内存
- sync:lock和waitgroup等内容,用于安全并发和携程同步
2. 依赖管理
2.1 go的依赖管理
go的依赖管理经历了三个阶段
- gopath
- go vender
- go module 广泛应用
目的是围绕版本的控制
2.1.1 gopath
存在弊端:在依赖同一个pkg的时候,如果pkg升级到v2后没有v1中的A功能了,那就会导致project A运行不了
2.1.2 govendor
在项目目录下增加vendor文件夹,存在当前项目依赖的副本。
优先vender的依赖,如果这里没有就去gopath下
可能存在的问题,这个是真离谱
2.1.3 gomodule
使用go.mod管理依赖包版本 通过 go get/go mod指令工具管理依赖包
2.2 依赖管理三要素
- 配置文件,描述依赖 go.mod
- 中心仓库管理依赖库 Proxy
- 本地工具 go get/mod
2.3.1 依赖配置 go.mod
example可以是github
如果项目很复杂,每个包都要单独引用的话,那每个包的文件夹下都要有go.mod
原声库:不同项目的go版本可能不一样
单元依赖:分成module path和版本号两部分,可以定位某一仓库的一次提交
2.3.2 依赖配置 version
版本号的规则定义,主要分成以下两种类型
语义化:
- major 大版本。不同major不兼容
- minor 新增函数功能,保证相同major是兼容的
- patch 做代码bug修复
基于commit伪版本
- 版本前缀:和语义化的major意义相同
- 时间戳:提交commit的时间戳
- hash码:对于本次提交的校验
2.3.3 indirect 间接依赖
2.3.4 incompatible
gomod是最近才有的,为了兼容之前打错了的版本号,需要用incompatible
这个建议自己再去查查
选择满足本次构建的最低版本,如果有1.5的话不会选择的
2.3.5 依赖分发
如果依赖都基于如github等第三方平台的话,可能会因为作者的更改等问题,导致后面用不了这个依赖了
因此提出了proxy的概念,会缓存依赖的所有版本,实现可靠的依赖分发
2.3.6 变量 goproxy
如果proxy1没有,就去proxy2搜,如果还没有就去原始站点搜
2.3.7 工具 go get
2.3.8 go mod工具
总结
- go.mod 配置文件,描述依赖
- proxy 中心仓库
- go get/mod 本地工具
3. 测试
- 回归测试:终端刷刷抖音
- 集成测试:对服务暴露的接口进行自动化测试
- 单元测试:开发阶段对单独函数验证
将函数和模块等内容,整合成测试单元,通过比较输入输出和期望的差异,进行校对。
3.1.1 单元测试规则
用_test.go结尾,可以区分源代码和测试代码
func TextXxx(*testing.T) 如果函数命名有问题,那么在ide中就不会显示运行的标志
初始化逻辑放到testmain中
3.1.4 assert
外部包已经帮忙实现equal了,不用自己写等不等于
3.1.5 代码覆盖率
开发的时候,应该保证函数的粒度足够小,也就是单一职责
3.2 单元测试的依赖
单元测试每次的结果都应该是一样的(迷瞪),且能够独立运行的(稳定)
打桩就是用一个函数替代另一个函数
unpatch就是卸载桩子
打桩后,就不用依赖文件了,直接返回
3.5 基准测试
负载均衡测试 看看别人的博客吧www.cnblogs.com/ssgeek/p/15…
4. 项目实践
定义topic(话题)和postlist(帖子)的结构体
E-R图模型实体,一对多,一个topic对应多个post
4.4 通用的分层结构
数据层关联底层数据模型,封装外部数据增删改查,通过本地操作拉取话题和帖子数据
业务层不关心底层数据存储,进行数据处理吧
controller封装数据
使用开源web框架
要根据id实现查询操作
id直接用map就行了
service层取值的逻辑
第二步准备数据的逻辑