GO进阶
- 语言进阶(并发视角看Go高性能本质)
- 依赖管理(了解Go语言依赖管理演进度)
- 测试(单元测试)
- 项目实战
01 并发和并行
1.1 Goroutine
- 协程 ( 用户态)轻量线程 kb
- 线程 内核态 mb
func hello(i int){
println("hello goroutine : " + fmt.Sprint(i))
}
func HelloGoRoutine(){
for i := 0; i < 5; i++{
go func(j int){
hello(j)
}(i) // 创建了一个匿名函数,并用 go 关键字启动该匿名函数作为一个 goroutine 运行。(i)表示 i 作为了参数传给了匿名函数
}
time.Sleep(time.Second)
}
1.2 协程通信(CSP模型)
协程通信的 CSP(Communicating Sequential Processes)模型是一种并发编程模型,主要用于描述和分析多任务、多个协程之间的通信与同步。CSP模型的核心思想是 进程之间通过通信进行交互,而非共享内存。每个进程都有自己的独立状态,进程间通过消息传递(通常是通过管道或者队列)进行协作。
1.3 Channel
- 无缓冲通道
- 有缓冲通道
生产消费模型
并发安全
但是go也保存了共享内存来通信的方式
1.4 并发安全 Lock
undefined 问题
1.5 WaitGroup
sleep 实现暴力的阻塞,但是不是优雅的(我们不知道子协程具体运行的时间)
计数器为 0 表示所有并发任务执行完成
package concurrence
import (
"fmt"
"sync"
)
func hello(i int){
println("hello goroutine : " + fmt.Sprint(i))
}
func HelloGoRoutine(){
var wg sync.WaitGroup // go标准库的一个同步工具,用于等待一组 goroutine
for i := 0; i < 5; i++{
go func(j int){
defer wg.Done()// 在每个 goroutine 的函数体结束被调用,确保在函数执行完毕时减少等待的 goroutine 数量。
hello(j)
}(i)
}
wg.Wait()
}
引入sync.WaitGroup,会在所有goroutine完成任务后才允许主线程继续执行
依赖管理
依赖是各种开发包
- 工程项目不可能根据标准库从0~1搭建
go的依赖管理:gopath -> go vendor -> go module
现在广泛应用的就是 go module
- 不同环境依赖的版本不同
- 控制依赖库的版本
2.1 GOPATH
缺点是 无法实现package多版本控制
2.2 Go Vendor
多了一个 vendor 的文件,优先从 vendor 中找(把依赖代码一并带入项目);py 则是创建虚拟环境
vendor 也有问题
- 无法控制依赖的版本
- 更新项目可能出现依赖冲突,导致编译错误
Go Module
go module 是go官方出的一个依赖管理系统,解决了上述的问题,实现了定义版本规则和管理项目依赖关系的目标
- 通过
go.mod文件管理依赖包版本 - 通过
go get/go mod指令工具管理依赖包
依赖管理三要素
- 配置文件,描述依赖 go.mod
- 中心仓库管理依赖库 Proxy
- 本地工具 go get/mod (类似于爪哇的maven)
依赖配置
-
版本的语义化定义
MAJOR MINOR PATCH
-
MAJOR
大版本,不同MAJOR间是代码隔离的
-
MINOR
新增函数,功能,在 MINOR 下要做到兼容
-
PATCH
代码版本的修复
-
-
基于 commit 伪版本
版本前缀(语义化)— 时间戳 — 提交12位的哈希前缀
关键字
- indirect 标识为非直接依赖
- 主版本 v2 以上 v3 v4 这种,路径都需要增加 /v3 这种后缀,允许不同版本之间是不相互兼容的
- incompatible 对没有 go.mod 文件并且主版本 2+ 的依赖,会标记一下,可能存在不兼容的代码。
依赖图
Go会通过算法选择最低兼容版本
依赖分发
这部分我们关注依赖去哪里下载,如何下载?
我们如果直接使用代码托管平台(Github, SVN, ...)下载下来的话,会有一些问题
- 无法保证构建稳定性/可用性(增/删/改软件版本)
- 增加第三方压力(平台负载问题)
所以出现了 Proxy ,没有什么是添加一个中间层解决不了的
Go moudle 是通过环境变量 GOPROXY 控制 Proxy 的
GOPROXY="https://proxy1.cn,https://proxy2.cn ,direct"
服务站点URL列表,“direct” 表示源站
先从 Proxy1 -> Proxy2 -> Direct;这和我们设计缓存的一些模式是相通的。
go get
go get 是 Go 语言的一个命令,用于 下载和安装 Go 包,并且自动更新项目中使用的依赖项。它可以从 GitHub、GitLab、Bitbucket 等代码托管平台
go mod
go mod 是 Go 语言用来管理依赖和模块的命令,它引入了 Go Modules 功能,从 Go 1.11 开始,旨在取代传统的 GOPATH 模式,使得 Go 语言的依赖管理更加简洁、可靠和可扩展。