线程&协程
首先来讲讲这两者的区别,后面的例子都会用线程来说明。
线程与协程的区别
- 协程是用户态,更加轻量级,是轻量级线程。
- 线程是内核态,比协程开销大。
并发并行
Go语言的依赖管理首先从多线程开始入手,学习视频带着我们认识了并发和并行,这两者都是多线程运行的方式,不同的是,并发是一个CPU轮流执行线程,那么当CPU在执行线程1时,线程2是被挂起的状态;而并行则是多个CPU执行线程,可以一起跑的状态。
- 并发:
- 并行:
几种状态
下面来复习一下线程的几个状态:
- New(新创建)
- Runnable(可运行)
- Blocked(被阻塞)
- Waiting(等待)
- Timed Waiting(计时等待)
- Terminated(被终止)
Blocked 与 Waiting 的区别
- Blocked 是在等待其他线程释放锁。
- Waiting 则是在等待某个条件,比如join的线程执行完毕,或者是被唤醒。
goroutine
Goroutine是Go语言的一种轻量级线程——协程,能够实现Go语言的多核执行,提升运行效率,减少开销。
func HelloPrint(j int){
println("hello goroutine : " + fmt.Sprint(j))
}
func main(){
for i := 0; i < 5; i++ {
go func(j int){
HelloPrint(j)
}(i)
}
time.Sleep(time.Second)
}
CSP(Communicating Sequential Processes)
- 通过共享内存实现通信
- 通过通道实现通信
- Channel
make (chan 元素类型,[缓冲大小])
make (chan int)
make (chan int, 2)
并发安全锁
有锁,能保证数值的一致性;无锁不能保证数值的一致性,数值有可能正确,也有可能错误。如何加锁:
var {
x int
lock sync.Mutex
}
lock.Lock
x += 1
lock.Unlock()
Waitgroup
Add(delta int): 计数器+delta
Done():计数器-1
Wait:阻塞直到计数器为0
先通过add方法,对计数器+5,然后开启协程,每个协程执行完后,通过Done对每个计数器-1,最后wait主协程阻塞,计数器为0时退出主协程。
func ManyGoWait() {
var wg sync.WaitGroup
wg.Add(5) //添加计数器的值
for i := 0; i < 5; i++ {
go func(j int) {
defer wg.Done() // -1
HelloPrint(j)
}(i)
}
wg.Wait() //阻塞,直到为0
}
依赖管理
依赖管理演进:GOPATH --> Go Vendor --> Go module,前面两个都没能很好的控制依赖版本的问题,下面来看go module
Go Module
依赖管理三要素
- go.mod 配置文件,描述依赖
- proxy 中心仓库管理依赖库
- go get/mod 本地工具,指令工具管理依赖包
版本
- 模块路径: 从模块路径可以看出哪里找到该模块,如果是
github前缀则表示可以从GitHub中仓库找到,依赖包的源代码由github托管
依赖标识:[Module Path][Version]
- 语义化版本
写法${MAJOR}.${MINOR}.${PACTH}, 不同的MAJOR版本表示不同的API,MINOR版本通常是新增的函数或者功能,向后兼容,PATCH版本一般是一些修复的bug
V1.3.0
- 基于commit伪版本
写法vx.0.0-yyyymmddhhmmss-abcdefgh1234,时间戳(提交时间)+校验码(哈希码前12位)
v0.0.0-20220401081311-c38frfrbfnnb4
2. indirect:间接依赖 3. incompatible
- 主版本2+模块会在模块路径增加/vN后缀。
- 对于没有go.mod文件且主版本2+的依赖,会+incompatible
对比Java中的maven
- setting.xml
- pom文件
go.mod & maven
Go 编译的时候,如果同一个程序的不同段的代码分别依赖不同版本的项目,会选择最低版本的编译
Java 会就近原则来选择,如下图,A会选择D1.0来依赖,因为路径更短;如果多个版本都有相同的最短路径,则会选择最先声明的版本进行上传
proxy
proxy是一个服务站点,里面存储了软件内容,可以从里面拉取依赖;go module通过GOPROXY环境变量控制如何使用Go Proxy;GOPROXY是一个站点URL列表,可以使用"direct"表示源站。
GOPROXY="
https://proxy1.cn,https://proxy2.cn,direct" 先在proxy1下载依赖,没有再向proxy2下载,如果还没有再去源站点下载依赖,缓存在proxy站点中
go get工具
go get example.org/pkg
@update 默认
@none 删除依赖
@v1.1.2 tag版本,语义版本
@2233df4 特定的commit
@master 分支最新的commit
go mod工具
init 初始化,创建go mod文件
download 下载模块到本地缓存
tidy 增加需要的依赖,删除不必要的依赖
!!!go.mod文件和go mod注意区分