Go语言进阶
Go routine
协程:用户态,轻量级线程
线程:内核态,线程跑多个协程
Go语言开启协程
只需要在调用函数时,在其前面加上关键字 go
go语言提倡通过通信共享内存,而不是通过共享内存(临界区)而实现通信
channel创建
make(chan 元素类型,[缓冲大小])
·有缓冲通道 make(chan int)
·无缓冲通道 make(chan int,2)
举例:
A子协程发送0-9数字,B协程计算输入数字的平方,主协程输出最后的平方数
package main
func CalSquare(){
src:=make(chan int)
dest:=make(chan int,3)
go func(){//协程A
defer close(src)
for i:=0;i<10;i++{
src<-i
}
}()
go func(){//协程B
defer close(dest)
for i:=range src{
dest<-i*i
}
}()//主协程
for i:=range dest{
println(i)
}
}
func main(){
CalSquare()
}
并发安全性
通过对5个协程的并发执行,对协程不加锁,任由其对临界区自由执行,以及对临界区加锁,按顺序执行的比较示例:每个协程对变量执行2000+1此操作,用sleep设置时间延时
package main
import (
"sync"
"time"
)
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)
}
func main(){
Add()
}
go语言通过WaitGroup可实现并发任务的同步,waitgroup有三个方法,Add,Done,Wait,Add(delta int)维护一个计数器,计数器+delta,Done计数器-1,wait实现阻塞直到计数器为0,计数器为0表示所有并发任务的完成
package main
import (
"fmt"
"sync"
)
func ManyGoWait(){
var wg sync.WaitGroup
wg.Add(5)
for i:=0;i<5;i++{
go func(j int){
defer wg.Done()
hello(j)
}(i)
}
wg.Wait()//通过wait进行阻塞
}
func hello(i int){
println("hello goroutine:"+fmt.Sprint(i))
}
func main(){
ManyGoWait()
}
依赖管理
依赖指各种安装包,工程项目不可能基于标准库0~1编码搭建,复杂项目可通过sdk引入相关依赖。
依赖管理方案
环境变量$GOPATH
项目代码直接依赖src下的代码
go get下载最新版本的包到src目录下
依赖管理的三要素
- 配置文件,描述依赖
- 中心仓库管理依赖库
- 本地工具
go vendor
项目目录下增加vendor文件,所有依赖包副本形式放在$ProjectRoot/vendor下
依赖寻址方式:vendor=>GOPATH
优点:通过每个项目引入一份依赖的副本,解决了多个项目需要同一个package依赖的冲突问题。
缺点:但是无法控制依赖的版本,更新项目又可能出现依赖冲突,导致编译出错
Go Module
通过go.mod文件管理依赖包版本
通过go get/go mod指令工具管理依赖包