1 语言进阶
1.1 并发和并行
并发:多线程程序在一个核的cpu上运行,交替使用;
并行:多线程程序在多个核的cpu上运行,同时进行。
1.2 Goroutine—协程
协程:用户态,轻量级线程,栈KB级别。
线程:内核态,线程跑多个协程,栈MB级别。
1.3 CSP(communicating Sequential Processes)
提倡通过通信共享内存而不是通过共享内存而实现通信。
使用make(chan元素类型,[缓冲大小])
- 无缓冲通道:make(chan int)
- 有缓冲通道:make(chan int,2)
// 例子:
func CalSquare(){
src := make(chan int)
dest := make(chan int, 3)
go func(){ // A
defer close(src)
for i := 0; i<10;i++{
src <- i
}
}()
go func(){ // B
defer close(dest)
for i := range src{
dest <- i
}
}()
for i := range dest { // M
println(i)
}
A子协程发送0~9数字
B子协程计算输入数字的平方
主协程输出最后的平方数
1.4 WaitGroup
计数器:开启协程+1,执行协程-1,主协程阻塞直到计数器为0
func hello(i int){
println("hello goroutine : " + fmt.Sprint(i))
}
func ManyGoWait(){
var lm sync.WaitGroup
lm.Add(5)
for i := 0;i<5;i++{
go func(j int){
defer lm.Done()
hello(j)
}(i)
}
lm.Wait()
}
2 依赖管理
2.1 Go依赖管理演进
GOPATH -> Go Vendor -> Go Module
不同环境(项目)依赖的版本不同
2.1.1 GOPATH
在GOPATH下:
- bin:项目编译的二进制文件
- pkg:项目编译的中间产物,加速编译
- src:项目源码
项目代码直接依赖src下的代码
go get 下载最新版本的包到src目录下
弊端:当项目A和B依赖于某一个package的不同版本时,无法实现package的多版本控制
2.1.2 Go Vendor
项目目录下增加vendor文件,所有依赖包副本形式放在$ProjectRoot/vendor
依赖寻址方式: vendor => GOPATH
通过每个项目引入一份依赖的副本,解决了多个项目需要同一个package依赖的冲突问题。
弊端:无法控制依赖的版本。
更新项目又可能出现依赖冲突,导致编译出错。
2.1.3 Go Module
- 通过go.mod文件管理依赖包版本
- 通过go get/go mod指令工具管理依赖包
- 目标:定义版本规则和管理项目依赖关系
2.2 依赖管理三要素
- 配置文件,描述依赖 go.mod
- 中心仓库管理依赖库 Proxy
- 本地工具 go get/mod
2.3.1 依赖配置—go.mod
2.3.2 依赖配置—version
- 语义化版本
V1.3.0、V2.3.0 - 基于commit 伪版本
vX.0.0-yyyymmddhhmmss-abcdefgh1234
v0.0.0-20220401081311-c38fb59326b7
v1.0.0-20201130134442-10cb98267c6c\ - indirect:间接依赖
- incompatible:主版本2+模块会在模块路径增加/vN后缀。
对于没有go.mod文件并且主版本2+的依赖,会+incompatible。
2.3.3 依赖分发—回源
- 无法保证构建稳定性,增加/修改/删除软件版本
- 无法保证依赖可用性,删除软件
- 增加第三方压力,代码托管平台负载问题
- 依赖分发—proxy
2.3.4 工具—go get
go get example.org/pkg
- @update 默认
- @none 删除依赖
- @v1.1.2 tag版本,语义版本
- @23dfdd5 特定的commit
- @master 分支的最新commit
2.3.5 工具—go mod
go mod:
- init:初始化,创建go.mod文件
- download:下载模块到本地缓存
- tidy:增加需要的依赖,删除不需要的依赖