2.Go工程实践| 青训营笔记

83 阅读5分钟

这是我参与「第五届青训营 」伴学笔记创作活动的第 2 天

1.语言进阶,并发编程

Go是为了并发而生的。

1.1 协程vs线程

协程:用户态,轻量级线程,栈MB级别。创建和调度由go本身实现。线程可以跑多个协程。go一次可以创建上万协程,所以适合高并发场景。

线程:内核态,线程跑多个协程,栈KB级别。

1.2 快速开启一个协程

只需要在函数前面加一个go关键字即可。

下图的time.Sleep是为了子协程执行完之前,主协程不退出。

image.png

1.3 协程之间的通信

通过通信来共享内存,而不是通过共享内存来实现通信。

通道channel 一个goRoutine发给另一个goRoutine的机制。

右图是共享内存来实现数据交换,共享内存实现通信。必须通过互斥量对内存进行加锁。可能会影响性能,所以提倡通信共享内存。

image.png

1.4 Channel

下图是有缓冲通道和无缓冲通道。有缓冲通道设定通道大小。

image.png

例子:生产者消费者(共享内存实现通信)

src实现了A和B协程的通信。B的计算逻辑,计算平方放入dest,打印。 image.png

1.5 并发安全Lock

对x进行2000次+1操作。 image.png

1.6 WaitGroup

WaitGroup内部: image.png

一个简单的例子: image.png

2.依赖管理

Go依赖管理演进路线,每个阶段解决的问题

gopath->go vendor->go moudle

2.1 gopath

gopath是go语言的环境变量,是一个工作区。项目下所有依赖都在src中,通过go get下载最新版本到src中。

image.png 下图,A和B项目无法全部构建成功。

image.png

2.2 go Vendor

vendor中存了项目依赖的副本,项目依赖优先从vendor找,找不到再找goroot。这样就实现了版本控制。

image.png

问题,可能冲突,其实就是源码没办法标明版本。

image.png

2.3 go module(目前用的都是这个)

image.png

类比maven。 image.png

go.mod详细讲解

模块路径,标识了模块,可以看到从哪里能找到这个模块。

最关键的是描述单元依赖,由modulepath和版本号构成,可以唯一定位一个仓库的某一个版本。 image.png

goproxy:

image.png

go get:

image.png

go mod:

每次下载之前都可以go mod tidy一下,减少构建整个项目的时间。 image.png

3.单元测试

上线最后一环,对测试方法的渗透讲解。

自动化,通过服务暴露的一些端口测试。

单元测试,单独的函数模块测试。

3.1 单元测试

包含:输入,测试单元,输出

image.png

单元测试的规则,以_test.go结尾 TestMain我理解为测试函数的装饰器 image.png

举个例子:

image.png

下图是用go test运行,得到结果。

image.png

修复完,结果是这样的:

image.png

评估单元测试,用代码覆盖率评价。表示了测试用例的覆盖度。66.7%是执行了前两行代码,已经被验证过了,所以2/3=66.7%。

下图的例子是一个判断是否及格的函数。用--cover测试覆盖率。

image.png

提高测试率,保证测试的完备性。一般的覆盖率:50%~60%,较高的覆盖率达到80%:

对于一些资金类,要求覆盖率提高到80%以上。函数的单一职责能够更好的提高覆盖率。

image.png

幂等性和稳定性,

幂等性是重复运行一个case的时候,前后结果一致。 稳定性是单元测试能够相互隔离,任何时间函数能独立运行。 image.png

举个例子: image.png

3.2 mock测试

mock的组件有很多,随便选了一个mock的开源包。 image.png

target原函数,replacement需要替换的函数(打桩函数)。Unpatch是函数结束后需要把桩拔出。

image.png

用monkey举个例子(不对file文件的强依赖,文件没了被改了能照常运行):

image.png

3.3 基准测试

热点代码性能瓶颈问题。

image.png

多协程并行,性能劣化,因为rand。 image.png

用fastrand进行测试,性能提高了百倍。 image.png

4.项目实战

真实项目构造一个简单需求模型,需求分析逻辑设计,代码开发。 image.png

回帖,点赞,回帖列表回复。

image.png

用例分析:

image.png

ER图 image.png

分层模型: Service对数据层的数据进行打包封装,视图层包装一些视图格式。 image.png

4.1 创建项目,导入依赖

image.png

4.2 结构体创建

image.png

查询:全局扫描,效率不高,引入索引的概念。 map时间复杂度是O(1)很快的查到。

下图是定义的两个索引。因为这里是文件操作,所以要手动变map作为索引,用数据库直接有索引了。 image.png

image.png

上面两个红色的框可以理解为单例模式,让性能更好。最下面是根据id查询的方法。 image.png

4.3 Service层

首先对topicId做一个非法检验,比如非0之类的,然后拿数据。

image.png

代码:

进行一些检验,通过了返回数据 image.png

返回数据调用的方法,两个查询方法获取话题数据和回帖列表数据,两个流程没有前后相互依赖,用并行执行,提高执行效率。用WaitGroup,两个协程。最后等待,让话题信息和回帖信息完成,再返回。

image.png

4.4 Controller层

  1. Code,是否成功,用0和非0表示。
  2. 类型转换
  3. 转换成功通过service查询到封装的页面,再对PageData打包。 image.png

4.5 通过gin搭建web框架

  1. 初始化数据索引
  2. 初始化
  3. 构建路由
  4. 启动服务

image.png

最后就可以运行了。 go run server.go

image.png

image.png

作业:发帖。

需要注意:生成帖子,帖子ID需要不重复,唯一性。新生成帖子在文件末尾不要给顶掉。发帖要注意并发读写的并发安全问题。(因为老师是一个文件,所以需要注意这个。)