这是我参与「第五届青训营 」伴学笔记创作活动的第 2 天
1.语言进阶,并发编程
Go是为了并发而生的。
1.1 协程vs线程
协程:用户态,轻量级线程,栈MB级别。创建和调度由go本身实现。线程可以跑多个协程。go一次可以创建上万协程,所以适合高并发场景。
线程:内核态,线程跑多个协程,栈KB级别。
1.2 快速开启一个协程
只需要在函数前面加一个go关键字即可。
下图的time.Sleep是为了子协程执行完之前,主协程不退出。
1.3 协程之间的通信
通过通信来共享内存,而不是通过共享内存来实现通信。
通道channel 一个goRoutine发给另一个goRoutine的机制。
右图是共享内存来实现数据交换,共享内存实现通信。必须通过互斥量对内存进行加锁。可能会影响性能,所以提倡通信共享内存。
1.4 Channel
下图是有缓冲通道和无缓冲通道。有缓冲通道设定通道大小。
例子:生产者消费者(共享内存实现通信)
src实现了A和B协程的通信。B的计算逻辑,计算平方放入dest,打印。
1.5 并发安全Lock
对x进行2000次+1操作。
1.6 WaitGroup
WaitGroup内部:
一个简单的例子:
2.依赖管理
Go依赖管理演进路线,每个阶段解决的问题
gopath->go vendor->go moudle
2.1 gopath
gopath是go语言的环境变量,是一个工作区。项目下所有依赖都在src中,通过go get下载最新版本到src中。
下图,A和B项目无法全部构建成功。
2.2 go Vendor
vendor中存了项目依赖的副本,项目依赖优先从vendor找,找不到再找goroot。这样就实现了版本控制。
问题,可能冲突,其实就是源码没办法标明版本。
2.3 go module(目前用的都是这个)
类比maven。
go.mod详细讲解
模块路径,标识了模块,可以看到从哪里能找到这个模块。
最关键的是描述单元依赖,由modulepath和版本号构成,可以唯一定位一个仓库的某一个版本。
goproxy:
go get:
go mod:
每次下载之前都可以go mod tidy一下,减少构建整个项目的时间。
3.单元测试
上线最后一环,对测试方法的渗透讲解。
自动化,通过服务暴露的一些端口测试。
单元测试,单独的函数模块测试。
3.1 单元测试
包含:输入,测试单元,输出
单元测试的规则,以_test.go结尾
TestMain我理解为测试函数的装饰器
举个例子:
下图是用go test运行,得到结果。
修复完,结果是这样的:
评估单元测试,用代码覆盖率评价。表示了测试用例的覆盖度。66.7%是执行了前两行代码,已经被验证过了,所以2/3=66.7%。
下图的例子是一个判断是否及格的函数。用--cover测试覆盖率。
提高测试率,保证测试的完备性。一般的覆盖率:50%~60%,较高的覆盖率达到80%:
对于一些资金类,要求覆盖率提高到80%以上。函数的单一职责能够更好的提高覆盖率。
幂等性和稳定性,
幂等性是重复运行一个case的时候,前后结果一致。
稳定性是单元测试能够相互隔离,任何时间函数能独立运行。
举个例子:
3.2 mock测试
mock的组件有很多,随便选了一个mock的开源包。
target原函数,replacement需要替换的函数(打桩函数)。Unpatch是函数结束后需要把桩拔出。
用monkey举个例子(不对file文件的强依赖,文件没了被改了能照常运行):
3.3 基准测试
热点代码性能瓶颈问题。
多协程并行,性能劣化,因为rand。
用fastrand进行测试,性能提高了百倍。
4.项目实战
真实项目构造一个简单需求模型,需求分析逻辑设计,代码开发。
回帖,点赞,回帖列表回复。
用例分析:
ER图
分层模型:
Service对数据层的数据进行打包封装,视图层包装一些视图格式。
4.1 创建项目,导入依赖
4.2 结构体创建
查询:全局扫描,效率不高,引入索引的概念。 map时间复杂度是O(1)很快的查到。
下图是定义的两个索引。因为这里是文件操作,所以要手动变map作为索引,用数据库直接有索引了。
上面两个红色的框可以理解为单例模式,让性能更好。最下面是根据id查询的方法。
4.3 Service层
首先对topicId做一个非法检验,比如非0之类的,然后拿数据。
代码:
进行一些检验,通过了返回数据
返回数据调用的方法,两个查询方法获取话题数据和回帖列表数据,两个流程没有前后相互依赖,用并行执行,提高执行效率。用WaitGroup,两个协程。最后等待,让话题信息和回帖信息完成,再返回。
4.4 Controller层
- Code,是否成功,用0和非0表示。
- 类型转换
- 转换成功通过service查询到封装的页面,再对PageData打包。
4.5 通过gin搭建web框架
- 初始化数据索引
- 初始化
- 构建路由
- 启动服务
最后就可以运行了。 go run server.go
作业:发帖。
需要注意:生成帖子,帖子ID需要不重复,唯一性。新生成帖子在文件末尾不要给顶掉。发帖要注意并发读写的并发安全问题。(因为老师是一个文件,所以需要注意这个。)