go并发
并发
go实现了两种并发形式,一种是多线程共享内存,另一种就是Go、语言推荐的CSP并发模型。
“不要以共享内存的方式来通信,相反,要通过通信来共享内存。”
1. Goroutine
线程->协程
相信大家都多多少少的了解到了线程,那么协程是什么存在呢?
- 协程,是一种比线程更加轻量级的存在。正如一个进程可以拥有多个线程一样,一个线程也可以拥有多个协程。
- 协程不是被操作系统内核所管理,而完全是由程序所控制。(性能有所提升)
- 协程能保留上一次调用的状态,每次重入时,就相当于进入上一次调用的状态。
程序示例
程序简单演示了使用go关键字创建多个协程。
这里有一点,如果在主函数使用go goroutine() fmt.Println("........"),那么程序只会输出........。
当协程创建完毕之后,主函数立即返回继续执行下一行代码,不像函数调用,需要等函数执行完成。主协程执行完毕,程序便退出,goroutine 协程随即也退出,便不会有输出。
如果想要协程执行完成的话,可以加一个休眠时间
func goroutine() {
for i := 0; i < 5; i++ {
go func(j int) {
hello(j)
}(i)
}
}
func hello(i int) {
fmt.Println("hello goroutine : " + fmt.Sprint(i))
}
执行结果:
hello goroutine : 4
hello goroutine : 1
hello goroutine : 3
hello goroutine : 0
hello goroutine : 2
2. CSP (communicating sequential processes)
CSP并发模型通过goroutine和channel来实现的
3. channel
使用make(chan 元素类型,[缓冲大小])可以生成一个channel,传输数据使用channel <- 数据, 接受数据使用 <- channel。
src := make(chan int)
dest := make(chan int, 3)
go func() {
defer close(src) //用于资源的释放,会在函数返回之前进行调用
for i := 0; i < 10; i++ {
src <- i
}
}()
go func() {
defer close(dest)
for i := range src {
dest <- i * i
}
}()
for i := range dest {
fmt.Println(i)
}
4. 并发安全Lock
锁机制,我们下面使用的Mutex是互斥锁的意思,也叫排他锁,同一时刻一段代码只能被一个线程运行,使用只需要关注方法Lock和Unlock。
在不加锁的情况下,多协程去执行代码出现的结果可能不一,(我执行了几次大概三千左右),而加上锁之后,结果都是5000。因为加上锁之后协程都会去执行++操作。
//mutex := sync.Mutex{}
x := 0
for i := 0; i < 5; i++ {
go func() {
for j := 0; j < 1000; j++ {
//mutex.Lock()
x++
//mutex.Unlock()
}
}()
}
fmt.Println(x)
5. WaitGroup
waitgroup,等待其他协程执行完一些代码,等待获取结果。是一种常见的并发控制方式,有点类似于信号量,常用的有三个方法。
- ADD(delta int) // 初始化计数器的值
- Done() //计数器-1
- Wait()// 阻塞,直到计数器的值为0后才会解除状态
依赖管理
1. go依赖演进
GOPATH =>Go Vendor =>Go Module
- go PATH 弊端:无法实现多版本的控制
- go Vender 弊端:会存在依赖冲突
- go Module
go.mod 是 go 管理第三方依赖的一种方式
准确记录项目依赖:当前项目使用了哪些第三方包、依赖包的版本
可重复构建:当前项目在任何环境或平台构建产物相同
2. 依赖管理三要素
- 配置文件,描述依赖 go.mod
- 中心仓库管理依赖库 Proxy
- 本地工具 go get/mod
3. 依赖配置
go module的下载问题:
比较常见的是GitHub,但是我们都知道github访问时不稳定的,所以用该平台可能会存在一些问题:
- 无法保证构建稳定性,可能存在增加、修改、删除软件版本。
- 无法保证依赖可用性,软件被删除
- 增加第三方压力,代码托管平台负载问题
Proxy是一个服务站点,通过它可以拉取依赖。
go get
go get example.org/pkg + 参数
- @update 默认参数
- @none 删除依赖
- @v1.1.2 指定tag版本,语义版本
- @23dfdd5 特定的commit版本
- @master 指定分支的最新commit
go mod
go mod + 参数
- init 初始化,创建go.mod文件
- download 下载模块到本地缓存
- tidy 增加需要的依赖,删除不需要的依赖
学习记录使用