GO进阶课笔记 | 青训营笔记

78 阅读5分钟

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

一、本堂课重点内容:

  • Goroutine
  • Channel
  • Sync
  • 依赖管理
  • 测试
  • 实战开发简单web服务器

二、详细知识点介绍:

Channel

GO更推荐通过通信实现共享内存而不是通过共享内存实现通信。 Channel的本质类似一个阻塞队列,分为有缓存和无缓存 无缓存的Channel用来实现协程同步,有缓存则是异步的

WaitGroup

底层维护一个计数器,实现线程同步 有三个函数,分别是Add(delta int)作用是使得计数器加delta Done()使得计数器减一,一般在子协程工作完毕后执行 Wait()阻塞等待直到计数器为0,一般在主协程使用

依赖管理

复杂项目中需要依赖很多库,GO有三种方法实现依赖管理:GOPATH、GO Vendor、Go Module,最常用的是Go Module

GOPATH:环境变量$GOPATH其实就是GO的根目录,里面有三个文件,分别是bin(项目编译的二进制文件)、pkg(项目编译的中间产物,起到加速编译的作用)、src(项目源码), 这种方式下,项目代码直接依赖src下的代码,需要下载更新包需执行go get下载最新版本的包到src目录下。缺点是无法实现package的多版本控制,比如src中某个包升级了,那么其他所有依赖升级包的包都会受到影响,如果不跟着升级的话可能无法正常编译

Go Vender:为了解决GOPATH的弊端诞生了Go Vender。其实就是再$GOPATH下多了一个vender文件夹,存放一些包的副本,编译时会首先从vender文件夹中寻找依赖包,找不到再去src文件夹中寻找,本质上还是依赖源码,无法完美地控制以来的版本,可能出现依赖冲突,导致编译出错。(比如project A依赖包B和包C,而包B依赖包D1,包C依赖包D2,包D1和包D2是不兼容的,那么此时就出现了以来冲突)

Go Module: 版本:版本分为语义化版本和基于commit伪版本,语义化版本格式为 ${MAJOR}.${MINOR}.${PATCH},不同的MAJOR间不兼容,同一个MAJOR下的MINOR相互兼容,PATCH是一些代码的小更新修复。

特殊标识:在go.mod中,间接依赖要用// indirect标识。对于主版本2+的模块会在模块路径后加/vN后缀。对于没有go.mod文件并且主版本2+的依赖,要加+incompatible后缀。

配置依赖规则:配置依赖时选择最低的兼容版本,比如如果你的module,依赖的module A需要require C v1.3,依赖的module B需要require C v1.4,最小版本选择算法将会选择C的v1.4版本用于build。即使后期C有v1.5版本可用,未显式require至go.mod中,仍将使用C v1.4版本用于build。

依赖分发:若直接依赖代码仓库中的代码容易遇到问题,比如代码仓库的代码作者更改或删除了代码,那么可能导致之前能跑的程序因为依赖包的改变就不能跑了,也就是无法保证构建稳定性和依赖可用性,以及增加第三方代码托管平台的负载压力。为了解决以上问题引入Porxy,它可以缓存代码平台上的依赖代码(类似缓存)。

go mod语句:后可接三个关键词init(初始化,创建go mod文件)、download(下载模块到本地缓存)、tidy(增加需要的依赖,删除不需要的依赖)

测试的基本概念

测试分为三种类型

  • 回归测试:通过手动测试
  • 集成测试:对系统功能的自动化测试
  • 单元测试:开发者对单独的函数模块进行测试 从上到下,覆盖率变大,成本却降低,因此单元测试一定程度上决定代码质量
单元测试

规则:所有测试文件以_test.go结尾,测试函数命名为func TestXxx(*testing.T)(类似process即跑业务逻辑的函数),初始化逻辑放到TestMain(*testing.M)(类似主函数)当中。

覆盖率:就是通过跑完所有测试用例所需要运行的代码段占所有代码的比例。在go test命令结尾加--cover即可检测覆盖率。 提高覆盖率的方法:1.测试分支相互独立、全面覆盖 2.测试单元粒度足够小,满足函数单一原则

单纯的单元测试的不足之处:一个大项目需要很多外部依赖,比如DB、Cache、本地文件,在测试过程中可能因为网络等原因导致测试结果不同,而测试需要满足稳定性和幂等性(每次测试结果相同)。

Mock测试

需要测试的项目有许多依赖时可以利用Mock

Mock可以为一个函数或方法打桩。例如开源monkey库中的Patch函数就是打桩操作,可以拜托本地文件的依赖,在任何环境中运行。

基准测试

一句话说,基准测试就是测试性能的。

三、实践练习例子:

本次时间练习的项目架构主要分为三层:repository层、service层、controller层

  • repository层:主要负责存储数据,向service层提供数据
  • service层:从service层拿到数据后进行处理,执行业务逻辑,最后将得到的结果给controller层
  • controller层:处理与外部的交互逻辑

该项目流程就是:本地存放json文件,在repository层读取本地文件,存入结构体中,并用map设置索引,最终用户通过索引查询。service层通过controller层传来的id,在map中查询对应信息,并将信息返回给controller层,controller层简单封装一下信息。

主函数中用了Gin框架,Gin可以快速完成WEB开发,底层其实就是封装了net/http库。

r := gin.Default() //生成一个默认的gin
	r.GET("/community/page/get/:id", func(c *gin.Context) { //解析get方法,通过RESTful方式获得id
		topicId := c.Param("id") //保存id
		data := cotroller.QueryPageInfo(topicId) //向controller层传入数据跑业务逻辑
		c.JSON(200, data) //返回json格式
	})
	err := r.Run()

四、课后个人总结:

Go进行web开发十分迅速,并且有有非常多的测试方法,更重要的是可以非常简单地开发出一个并发程序,但在实践中要注意并发安全

五、引用参考:

gin-gonic.com/zh-cn/docs/… Gin官方文档