第二天笔记总结 | 青训营
- 并行:多线程在多个核的cpu上运行,是实现并发的一种手段
- 线程:栈MB级别
- 协程:KB级别
我的理解是并发可以提升单个核心的利用率,并行则是利用多个核心完成多项任务,因此并发可以提升并行的效率
goroutine
-
快速打印:开启协程打印
-
调用函数时在函数前加关键字 go
-
此时是并行乱序输出
CSP
- 提倡通过通信共享内存
- 通道连接协程,类似队列,保证收发数据的顺序
- 利用channal发送特定值到另一个Goroutine
Channel
- make( chan 元素类型,[缓冲大小])
- 无缓冲通道 make(chan int) 同步发送
- 有缓冲通道 make(chan int,2) 阻塞发送
这里阻塞的意思应该是预留出等待消费端依次处理数据的时间
A协程功能:生产0-9数字发送到src B协程功能:通过range遍历sre,计算平方发送到有缓冲通道dest
- 此时scr实现了A、B协程通信
- 保证了顺序性,是并发安全的
- 带缓冲的Channel令消费者的消费速度不影响生产者的效率,因为此时不论消费端是否完成,生产者都可以继续执行
并发安全Lock
对变量进行2000次+1操作,5个协程并发执行
- 加锁:通过Lock()和Unlock()实现,在每次加1之前获取临界区资源,执行后再释放
我认为这里的锁应该是悲观锁,默认数据会被修改
- 可见并发安全问题有一定概率影响结果,应控制临界区权限。
WaitGroup
由于无法知道子协程确切时间,无法精确使用sleep进行阻塞
- 使用waitgroup优化上面代码
- 由于有5个协程,因此add(5)
- 每个协程执行后,使用Done()对计数器减一,表明此子协程任务结束
- 最后通过wait进行阻塞
Go的依赖管理
依赖管理演进
GOPATH -> Go Vendor -> Go Module
GOPATH
- bin 存放项目编译的二进制文件
- pkg 项目编译的中间产物,加速编译
- src 项目源码
弊端
- 两个project依赖同一pkg的不同版本时,无法同时构建成功,无法实现pkg多版本控制
Go Vendor
- 项目目录下增加vendor文件夹,所有依赖包副本形式存放在$ProjectRoot/vendor中,优先从这里获取
- 将不同项目依赖的包放下相应项目vendor下,保证都能构建成功
弊端
无法控制依赖的版本
Go Module
- 通过go.mod文件管理依赖包版本
- 通过go get/mod指令工具管理依赖包
- Proxy 中心仓库管理依赖库
依赖配置
- MAJOR-不同版本间可以是代码隔离的
- MINOR-新增函数或功能,同一MAJOR保持前后兼容
- PATCH-代码bug的修复
解释了我们在app中见到的版本升级时版本号的命名规则,
indirect关键字
此时indirect标识非直接依赖
关键字incompatible
依赖配置
依赖C项目不同版本时,选择最低的兼容版本,如使用v1.3和v1.4时,最终编译为v1.4版本
依赖分发
Proxy缓存内容,保证依赖的可靠性,与设置缓存的模式类似
本地工具
go get/mod
测试
单元测试
测试不同函数、模块等,可以保证质量、提升效率,否则定位一个问题的周期会很长
我在跟着思路写代码时出现的错误:单元测试时输出应该是t.Error而不是自己定义输出 并且判断时如果调用t.Error会默认此时为FAIL
assert包
assert.Equal()即可判断是否输出正确
覆盖率
--cover参数,测试到的代码占比
依赖
幂等:重复运行case时结果不变 稳定:单元测试相互隔离,任何时间的函数独立运行
幂等这里我又搜了一下,在分布式系统中,正好可以用到前面学到过的加锁相关知识来实现,防止重复执行
Mock
打桩:A函数替换B函数,此时A为打桩函数 可以为一个函数/方法打桩,不再依赖本地文件
就是用模拟的情况来测试函数是否会出bug
基准测试
优化代码,需要对当前代码性能分析