并发
协程
多线程在一个核上运行称为并发,在多核上运行称为并行,Go语言有Goroutine,为协程,用户态,有Go语言控制,是轻量级线程,KB级别.而线程是内核态,一个线程可以运行多个协程,线程是MB级别.
-
启动协程
使用关键字
go+函数名,即可创建该函数的协程
通信(CSP)
Go提倡通过通信共享内存而不是通过共享内存来实现通信,因此要通过通道来实现不同协程间的通信,通道类似队列,先入先出.但Go也保留使用共享内存实现通信的功能,该功能需要加锁获取临界区权限,这样会发生竞争,影响并发效率
Channel
通过make(chan 元素类型,[缓冲大小])来创建一个通道,若不添加第二个参数则创建无缓冲通道,否则创建一个有缓冲通道,带有指定大小的缓冲区
生产消费模型示例
func main() {
src := make(chan int)
dest := make(chan int, 2)
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 {
println(i)
}
}
Lock锁
通过加锁来实现并发安全,通过以下方式创建变量并声明锁,然后通过lock.Lock()即可为该变量加锁
var(
x int64
lock sync.Mutex
)
WaitGroup并发同步
为了实现线程同步,可以使用time.sleep()方法,但更好的方法是通过WatiGroup进行优化
WaitGroup用于在执行多个 goroutine 时等待它们全部完成后再继续执行主程序。协调多个 goroutine 之间的同步,以确保所有 goroutine 都已完成其任务。
WaitGroup 包含以下几个主要方法:
Add(delta int): 用于增加等待的 goroutine 的数量。通常在启动一个新的 goroutine 之前调用Add方法,将等待计数器加一。Done(): 表示一个等待的 goroutine 已完成其任务。在 goroutine 完成其工作后调用Done方法,将等待计数器减一。Wait(): 阻塞主程序的执行,直到所有的 goroutine 都调用了Done方法,并且等待计数器归零。
依赖管理
开发项目中要学会站在巨人的肩膀上,使用已经开发完成的组件来帮助开发,避免重复发明轮子需要导入依赖,框架等,因此需要合理地管理依赖库,目前广泛应用Go Module
依赖管理的目标是解决不同环境(项目)的依赖版本不同以及控制依赖库的版本
GOPATH
Go语言的环境变量,该目录下
- bin: 项目编译的二进制文件
- pkg:项目编译的中间产物,加速编译
- src:项目源码
弊端是:若项目A和B依赖于同一package的不同版本,在升级过程中package函数可能发生改变,导致两个项目无法同时构建成功
Go Vendor
添加vendor,为每一个项目引入一份依赖副本,解决版本不同的问题
存在的问题是,package A和package B又依赖了不同的下一层package,而他们又不兼容,就会再次导致冲突
Go Module
通过go.mod文件管理依赖包版本,通过go get/go mod指令工具管理依赖包
依赖管理三要素:
- 配置文件,描述依赖 --- go.mod
- 中心仓库管理依赖库 --- Proxy
- 本地工具 --- go get和go mod