1、语言进阶
并发 VS 并行
1:多线程序在一个核的cpu上运行
2:多线程程序在多个核的cpu上运行
1.1 Goroutine
go可以充分发挥多核优势,高效运行
协程:用户态,轻量级线程,栈KB级别
线程:内核态,线程跑多个协程,栈MB级别
例:快速打印hello goroutine : 0~hello goroutine : 4
func hello(i int) {
println("hello goroutine : " + fmt.Sprint(i))
}
func HelloGoRoutine() {
for i := 0; i < 5; i++{
go func(j int) {
hello(j)
}(i)
}
time.Sleep(time.Second)
}
1.2 CSP(Communicating Sequential Processes)
提倡通过通信共享内存而不是通过共享内存而实现通信
1.3 Channel
make(chan 元素类型,[缓冲大小])
- 无缓冲通道 - make(chan int)
- 有缓冲通道 - make(chan int,2)
A 子协程发送0~9数字
B 子协程计算输入数字的平方
主协程输出最后的平方数
func CalSquare() {
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 {
//复杂操作
println(i)
}
}
1.4并发安全Lock
对变量执行2000次+1操作,5个协程并发执行
var (
x int64
lock sync.Mutex
)
func addWithLock {
for i := 0; i < 2000; i++ {
lock.Lock()
x += 1
lock.Unlock()
}
}
func addWithoutLock() {
for i := 0; i < 2000; i++ {
x += 1
}
}
func Add() {
x = 0
for i := 0; i < 5; i++ {
go addWithoutLock()
}
time.Sleep(time.Second)
println("WithoutLock:", x)
x = 0
for i := 0; i < 5; i++{
go addWithLock()
}
time.Sleep(time.Second)
println("WithLock:" x)
}
1.5WaitGroup
计数器
开启协程+1;执行结束-1;主协程阻塞直到计数器为0.
func hello(i int) {
println("hello goroutine : " + fmt.Sprint(i))
}
func HelloGoRoutine() {
for i := 0; i < 5; i++{
go func(j int) {
hello(j)
}(i)
}
time.Sleep(time.Second)
}
func ManyGoWait() {
var wg sync.WaitGroup
wg.Add(delta: 5)
for i := 0; i < 5; i++ {
go func(j int) {
defer wg.Done()
hello(j)
}(i)
}
wg.Wait()
}
2、依赖管理
2.1 Go 依赖管理演进
GOPATH ->Go Vendor -> Go Moudle
不同环境(项目)依赖的版本不同
控制依赖库的版本
2.1.1 GOPATH
环境变量$GOPATH
项目代码直接依赖src下的代码 GOPATH-弊端
A和B依赖于某一package的不同版本,无法实现package的多版本控制
2.1.2 Go Vendor-弊端
项目目录下增加vendor文件,所有依赖包副本形式放在$ProjectRoot/vendor 依赖寻址方式:vendor->GOPATH
通过每个项目引入一份依赖的副本,解决了多个项目需要同一个package依赖的冲突问题
无法控制依赖的版本,更新项目又可能出现依赖冲突,导致编译出错
2.1.3 Go Module
通过go.mod 文件管理依赖包版本
通过go get/go mod 指令工具管理依赖包
2.2 依赖管理三要素
1.配置文件,依赖描述 go.mod 2.中心仓库管理依赖库 Proxy 3.本地工具 go get/mod