Go语言上手-工程实践 | 青训营笔记
这是我参与「第三届青训营 -后端场」笔记创作活动的的第1篇笔记。 以提纲的形式简单记录下课上的一些要点内容。
一、语言进阶(并发编程)
1.并发:多线程程序在一个核的CPU上运行
并行:实现并发的一个手段,多线程程序在多个核的cpu上运行
2.线程、协程、进程
进程是具有特定功能的程序运行在数据集上的一次动态过程。是操作系统分配资源的最小单位,是应用程序运行的载体。一个进程可以有多个线程,进程之间相互独立,都有一块自己的内存空间。
线程是程序执行的最小单位,一个进程由一个或者多个线程组成,线程是进程中代码执行的不同路线。同一个进程中的各个线程共享程序的内存空间(包括代码段,堆和数据集,打开的文件),每个线程还会有自己的栈和寄存器,这些空间是每个线程独占的。
协程是一种用户态的轻量级线程,协程的切换完全由用户控制,协程间切换只需保存任务的上下文,没有内核的消耗。
3.go语言开启协程的方式:在调用的函数前加上go
4.提倡通过通信共享内存而不是通过共享内存来实现通信
5.channel的具体操作
①创建:make (chan 元素类型, [缓冲大小])
无缓冲通道:make(chan int)
有缓冲通道:make(chan int, 2)
6.WaitGroup(在Sync包下):用来实现并发任务的同步
WaitGroup的3个常用的方法:
①Add(delta int) 计数器+delta
②Done() 计数器-1
③Wait() 阻塞直到计数器为0
二、依赖管理 7.依赖:即各种开发包
8.go语言的依赖管理经历了三个阶段:GOPATH-->Go Vendor-->Go Module
广泛应用的是Go Module
迭代的目的:不同环境(项目)依赖的版本不同 控制依赖库的版本
9.GOPATH是go支持的一个环境变量,是一个go项目的工作区,这个目录下主要有三个关键目录。
①bin 项目编译生成的二进制文件
②pkg 项目编译的中间产物
③src 项目源码
注:项目代码直接依赖src下的代码
通过go get下载最新版本的包到src目录下
弊端:无法实现package的多版本控制
场景:ProjectA和ProjectB依赖于某一package的不同版本,记这两个版本为v1和v2,v1实现了A方法,这是项目A所依赖的方法;v2实现了B方法,是项目2所依赖的方法。v2没有做到上下兼容,如可能将A方法删掉了。由于依赖的是同一个src的源码,那么对于本地项目来说,项目A和项目B可能就无法同时创建成功。
10.为了解决GOPATH存在的问题,下一个阶段就是Go Vendor
项目目录下增加vendor文件,vendor里存放当前项目所依赖的副本,项目的依赖会优先从vendor目录下获取。如果vendor目录下没有,则会回源到GOPATH下寻找。
也就是说依赖寻址方式:vendor -> GOPATH
解决问题:通过每个项目引入一份依赖的副本,解决了多个项目需要同一个package依赖的冲突问题
弊端:无法控制依赖的版本,更新项目有可能出现版本冲突,导致编译出错
11.Go Module:go语言推出的依赖管理系统 解决了之前的问题
通过go.mod文件管理依赖包版本
通过go get/go mod指令工具管理依赖包
注:依赖管理三要素
①配置文件,描述依赖--->go.mod
单元依赖中每个依赖都由两部分组成,也就是说依赖标识:[Module Path] [Version/Pseudo-version]
版本规则:
[1]语义化版本
{MINOR}.${PATCH}
v1.3.0
v2.3.0
[1]基于commit伪版本
vx.0.0-yyyymmddhhmmss-abcdefgh1234
②中心仓库管理依赖库--->Proxy
③本地工具--->go get/mod
12.依赖分发
Proxy在使用过程中的配置:
go通过GOPROXY这个环境变量来控制proxy的配置的
GOPROXY = “proxy1.cn, proxy2.cn, indirect”
服务站点URL列表, “direct”标识源站(代表如果前面这些站点都没有依赖的话,会回源到第三方代码平台上去)
项目查找依赖的顺序:
Proxy1 ---> Proxy2 --->Direct
go mod的用法:
①go mod init 初始化,创建go.mod文件
②go mod download 下载模块到本地缓存
③go mod tidy 增加需要的依赖,删除不需要的依赖
三、测试(单元测试 Mock测试 基准测试)
13.单元测试
单元测试规则:
①所以测试文件以_test.go结尾
②命名规则:fun TestXxx(*testing.T)
③初始化逻辑放到TestMain中 fun TestMain(m *testing.M)
覆盖率:用于评估单元测试
go test judgment_test.go judgment.go --cover
单元测试--依赖
单元测试的两个目的:幂等、稳定
14.Mock测试
快速Mock函数:Patch() Unpatch()
为一个函数打桩
为一个方法打桩
注:打桩可以理解为用一个函数A去替换函数B,函数A是一个打桩函数,B是一个原函数
15.基准测试
建议:若有用随机的场景,推荐用fastrand而非rand
四、项目实战(需求设计 代码开发 测试运行)
需求描述:
社区话题页面
①展示话题(标题,文字描述)和回帖列表
②暂不考虑前端页面实现,仅仅实现一个本地Web服务
③话题和回帖数据用文件存储
Topic结构体
id
title
content
create_time
PostList结构体:
id
topic_id
content
create_time
Topic和PostList是一对多的关系
16.通用的分层模型:
17.组件工具
①Gin高性能go Web框架
推荐一篇介绍gin框架比较好的博客[www.liwenzhou.com/posts/Go/Gi…]
②Go Mod
go mod init
go get gopkg.in/gin-gonic/gin.v1@v1.3.0