go并发编程
并发VS并行
并发:多线程程序在一个核的CPU上运行
并行:多线程程序在多个核的CPU上运行
线程VS协程(Goroutine)
协程是用户态,可以理解为轻量级的线程,栈KB级别,是由Go运行时管理的并发执行的函数或方法
线程是内核态,线程一次可以并发的跑多个协程,栈MB级别
go语言更适合高并发场景,协程是'go'独有的
使用协程仅需要在函数或方法调用前加上 go 关键字
协程之间的通信
go语言提倡通过通信共享内存(channel通道)而不是通过共享内存而实现通信
Gorountine是go程序并发的一个执行体
channel通道
channel通道相当于把gorountine做一个连接
channel通道是一个引用类型可以通过make(chan 元素类型,[缓冲大小])来创建通道,可以根据是否有缓冲大小这一个参数将其分为有缓冲通道和无缓冲通道。
并发安全Lock
Sync(同步): sync 包
- Mutex(互斥锁):用于保护临界区,确保同一时间只有一个 Goroutine 可以进入临界区代码。防止多个 Goroutine 同时修改共享数据。
加Lock与否,决定并发是否安全,对临界区的控制,并发安全问题有一定概率发生,开发过程中应该尽量避免这种情况。
-
WaitGroup(等待组):用于等待一组 Goroutine 完成任务。它可以阻塞主 Goroutine,直到所有其他 Goroutine 完成工作。
-
有三个方法
-
ADD(x)计数器+delta
-
DONE()每个任务完成时,计数器-1
-
WAIT()阻塞使其等待直到计数器为0
-
-
go依赖管理
依赖指的用是前人研发好的包来进行依赖导入,实现各种功能
- 不同环境(项目) 依赖的版本不同
- 需要控制依赖库的版本
gopath
go语言支持的一个环境变量,是go项目的一个工作区
bin:项目编译的二进制文件
pkg:项目编译的中间产物,为了加速编译
src:项目源码
- gopath 实现的逻辑为:项目代码所有的依赖直接依赖src下的代码,也就是它会把所有的源代码都放在src下,并利用 go get下载最新版本的包到src目录下
- 弊端:无法实现package的多版本的控制
go Vendor
增加了一个vendor文件,将所有的依赖包的副本存放进去
这时候依赖就会优先从vendor中获取
- 通过每个项目引入一份依赖的副本,解决了多个项目需要同一个package依赖的冲突问题。
- 弊端:无法控制依赖的版本,更新项目有可能出现依赖冲突,导致编译出错
- 根本原因:也是依赖项目的源码,不能清晰的标识依赖版本的
go Module
通过go.mod 文件管理依赖包版本
通过go get/go mod指令工具管理依赖包
它实现了定义版本规则和管理项目依赖关系
-
依赖管理三要素
- 配置文件,描述依赖 go.mod
- 中心仓库管理依赖库 Proxy
- 本地工具go get/mod
-
go mod init 初始化,创建go.mod文件
-
go mod download 下载模块到本地缓存
-
go mod tidy 增加需要的依赖,删除不需要的依赖(可以在每次使用前运行一次)