这是我参与「第五届青训营 」伴学笔记创作活动的第 2 天,今天学习的内容是Go的并发编程以及依赖管理,整理学习笔记如下。
3 Go语言上手 - 工程实践
3.1 Go语言进阶 - 并发编程
从并发编程的视角了解Go高性能的本质
并发&并行
Go可充分发挥多核优势,高效运行
3.1.1 Goroutine 协程
协程: 用户态,轻量级线程,栈MB级别;
线程: 内核态,线程跑多个协程,栈KB级别。
创建方法
使用普通函数创建: go 函数名(参数列表)
使用匿名函数创建:
go func(参数列表){
函数体
}(调用参数列表)
3.1.2 CSP (Communicating Sequential Processes)
Go提倡通过通信共享内存而非通过共享内存实现通信
通过设置临界区来进行通信的话,很容易发生竞争等问题;而通过通道进行共享可以避免这个问题。
3.1.3 Chanel 缓冲通道
创建方法: make(chan 元素类型,[缓冲大小])
无缓冲通道(同步化),创建 make(chan int)
有缓冲通道,速度平衡,创建 make(chan int,2)
生产者消费者问题中使用有缓冲通道平衡结果输出与结果打印速度,避免因结果打印速度较慢导致数据丢失。
3.1.4 并发安全Lock
互斥锁简单声明调用
lock sync.Mutex //声明
lock.Lock() //加锁
lock.Unlock() //解锁
协程Goroutine中对临界区进行操作时需要加锁进行处理避免数据并发安全问题。
3.1.5 WaitGroup
通过计数器可以在主线程中等待Goroutine执行完成退出
3.1.4&3.1.5参考文档 - Go的同步sync:pkg.go.dev/sync
3.2 Go语言进阶 - 依赖管理
了解Go语言依赖管理的演进路线
3.2.1 Go 依赖管理演进
3.2.2 GOPATH
- 环境变量
$GOPATH
-
项目代码直接依赖
src下的代码 -
通过
go get下载最新版本的包到src目录下
弊端: 无法实现package的多版本控制(当某一package的某一被调用方法在不同版本可能未实现/实现不同)
3.2.3 Go Vendor
- 在项目目录下增加
vendor文件,所有依赖包的副本形式放在$ProjectRoot/vendor下
- 依赖寻址方式:
vendor->GOPATH(先寻找项目根目录下的vender文件夹,若没有再到GOPATH中) - 每个项目可以保证自己的包版本满足自己的使用需求
弊端: 无法控制依赖版本,当项目更新时可能出现依赖冲突,导致编译错误。
3.2.4 Go Module
目标: 定义版本规则和管理项目依赖关系
- 通过
go.mod文件,管理依赖包版本 - 通过
gp get / go mod指令工具管理依赖包
go mod 常用命令:
-
用
go help module-get和go help gopath-get分别去了解 Go modules 启用和未启用两种状态下的 go get 的行为 -
用
go get拉取新的依赖go get golang.org/x/text@latest拉取最新的版本(优先择取 tag)go get golang.org/x/text@master拉取 master 分支的最新 commitgo get golang.org/x/text@v0.3.2拉取 tag 为 v0.3.2 的 commitgo get golang.org/x/text@342b2e1拉取 hash 为 342b231 的 commit,最终会被转换为 v0.3.2
-
go get -u更新现有的依赖 -
go mod download下载 go.mod 文件中指明的所有依赖 -
go mod tidy整理现有的依赖 -
go mod graph查看现有的依赖 结构 -
go mod init [模块名]生成并初始化go.mod文件 -
go mod edit编辑go.mod文件-require gopkg.in/gin-gonic/gin.v1@v1.3.0向go.mod文件中加入该依赖
-
go mod vendor导出现有的所有依赖(事实上 Go modules 正在淡化 Vendor 的概念) -
go mod verify校验一个模块是否被篡改过(使用go.sum校验哈希值)
3.2.5 依赖管理三要素
-
配置文件,描述依赖 -
go.mod版本规则:
语义化版本 -
${MAJOR}.${MINOR}.${PATCH}。major为大版本,不要求兼容;minor为小版本,一般用于增加函数/功能等;patch为补丁,一般用于bug修复等。(e.g. V1.3.0, V2.3.0)基于
commit的伪版本 -vX.0.0-yyyymmddhhmmss-abcdefgh123。前面版本号部分规则与语义化版本相同,后面为时间戳与hash校验码。indirect直接依赖:
当前项目A依赖关系
A->B->C,则对B为直接依赖,对C为间接依赖。incompatible不兼容标示:
-
主版本在v2以上的模块Go要求其在模块路径必须有一个匹配的主版本后缀
/vN,这允许go命令将一个项目的多个主要版本视为不同的模块,即使它们是在同一个仓库开发的。 -
但由于其要求较晚提出,而部分库已经发布。为了与这些存储库保持兼容性,go 命令将
+incompatible后缀添加到具有主要版本 2 或更高版本的版本,而无需go.mod文件。+incompatible表示版本是与具有较低主要版本号的版本相同的模块。因此,go 命令可以自动升级到更高的+incompatible版本,即使它可能会破坏构建。
最低兼容版本:
Go会选择当前项目依赖的某个库的最低兼容版本作为依赖版本。
- (C项目
v1.4兼容v1.3版本)
-
-
中心仓库管理依赖库 -
Proxy作用: 缓存软件版本,保证依赖的稳定性
配置: 配置环境变量
GOPROXY -
本地工具 -
go get/mod