这是我参与「第五届青训营 」伴学笔记创作活动的第 2 天
依旧是不长的课程看半天呢 >.<
本节课主要关于工程应用的部分,主要是多协程与版本依赖问题
课程笔记二 Go语言进阶
语句入门
Goroutine(协程)
并行与并发
Go语言可以充分发挥多核计算机的优势,高效运行
线程与协程
这是课程中关于线程与协程的图。线程比较消耗资源,协程更加轻量,由go语言进行操作,可以并发的跑多个协程
但图中有错误,协程应该是栈KB级别,线程为栈MB级别
go语言中开启协程
只需简单的在函数调用前加一个go,便可以开启协程的运行,具体例子可以看以下内容
CSP(Communicating Aequential Processes)
GO语言推荐协程之间通过通信而共享内存,而不是通过共享内存而实现通信,以下为课程图
虽然go语言依旧支持通过共享内存来实现通信的机制,但是具有并发安全性问题,因为共享内容的原因,有可能存在几个协程同时对内存进行操作的问题。
Channel
channel是一种引用类型,通过make创建
make(chan 元素类型,[缓冲大小])
特别的在此处会用到一个操作符<-,比如
ch <- v发送值v到channel ch中
x := <-ch从channel ch中接收数据并赋值给v
不写缓冲大小即为无缓冲通道(也称为同步通道)
这里的缓存通道类似于一个待处理内容的存放区
defer close(sec)做了一个延迟的资源关闭
func CalSquare(){
src := make(chan int)
dest := make(chan int, 3)
go func() { //该协程发送0-9
defer close(sec)
for i:= 0; i<10; i++ {
src <- i
}
}()
go func() { //该协程计算输入数字的平方
defer close(dest)
for i:= 0; i<10; i++ {
dest <- i
}
}()
for i := range dest {
输出
}
并发安全Lock
func addWithlock(){
for i := 0; i<2000; i++ {
lock.Lock() //锁
x += 1
lock.Unlock //解锁
}
}
func addWithoutLock(){
for i:= 0; i<2000; i++ {
x+=1
}
}
for i := 0; i < 5; i++ {
go addWithlock() //开启协程
}
未加锁的部分同理
以上中为加锁的最终运行为10000
而未加锁的输出结果位置,结果可能小于10000,出现问题,如上所说的并发安全问题
应避免该情况出现,这也是前面通信再共享内存的原因
WaitGroup
计数器为0时表示所有任务完成,个人认为是可以高效顺承接下去部分代码的运行,而不用设置固定的sleep时间,提高性能。
依赖管理
工程项目相对复杂,不适合基于标准库从零开始编程,因此需要依赖包
go的依赖管理经过了三个阶段
graph TD
GOPATH --> Vendor --> Module
GOPATH --> Go Vendor --> Go Module
不同项目以来的版本或许不同,因此对于依赖版本的控制就相当重要
GOPATH
项目代码直接依赖src下的代码
很明显存在一个弊端,无法实现package的多版本控制。
Go Vendor
每个项目引入一个依赖的副本在vendor文件下,先寻址vender,若没有再寻址GOPATH,
解决了多个项目依赖同一个package的多版本问题,但可能会出现不同的package版本不兼容的问题
Go Module
通过go.mod文件管理依赖包版本 通过go get/go mod指令管理工具 1.11引入 1.16以后默认开启
依赖分发问题
若是直接使用版本仓库下载依赖会有问题,由于版本仓库软件作者会对软件版本进行改动,甚至时删除,并且作为一个存放的仓库,会增添第三方的压力
Proxy
Proxy作为一个服务站点,会缓存原站中的内容并不会改变,
从proxy拉取依赖,而proxy从各仓库缓存,保证了依赖的稳定性
Go mod/get (管理工具
Go mod init 初始化,项目的开始
Go mod download 下载模块到软件缓存
Go mod tidy 增加需要的依赖,删除不需要的依赖
关于后面的实践项目, 打算另外写一篇实践篇的笔记, 还需要酝酿>.<