GO——第二站
1.并发VS并行
- 多线程程序在一个核cpu上运行
- 多线程程序在多个核的cpu上运行
(1)Goroutine
用户态:多个协程,栈KB级别,轻量级线程
内核态:多个线程,栈MB级别,一个线程并发跑多个协程
(2)举例
test1.go
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)
}
2.CSP(Communicating Sequential Processes)
(1).通过通信共享内容(go提倡)
(2).通过共享内容而实现通信
3.Channel
make(chan 元素类型,[缓冲大小]) make(chan int)//无缓冲大小 make(chan int 2)//大小为2的有缓冲通道 通过缓冲通道发送信息给终点,重点再对通道进行遍历,读取数据。 test1.go
func AB3(){
//定义src是无缓冲大小的通道
//定义dest是缓冲大小为3的通道
src:=make(chan int)
dest:=make(chan int,3)
//A子协程
go func(){
defer close(src)
for i:=0;i<10;i++{
src <-i
}
}()
//B子协程
go func(){
defer close(dest)
for i:=range src{
dest <- i*i
}
}()
//主协程
for i:=range dest{
fmt.Println(i)
}
}
4.并发安全
通过“加锁”操作,解决高并发问题。设置sleep阻塞并发操作1,但事先你并不知道上一个并发操作会在何时结束。在实际开发中,应尽量避免对并发数据的读取和使用。 test1.go
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)
}
5.WaitGroup
实现并发任务的同步 Add():开启一个协程,该方法使计数器+1 Done():结束一个进程,该方法使计数器-1 Wait():阻塞直到计数器为0 test1.go
func ManyGoWait(){
var wg sync.WaitGroup
wg.Add(5)//计数器为5,表示有5个协程没有进行
for i:=0;i<5;i++{
go func(j int){
defer wg.Done()//-1个协程
hello(j)
}(i)
}
wg.Wait()
}
6.依赖管理
GOPATH->Go Vendor->Go Module
$GOPATH
项目代码直接依赖src下的代码 go get 下载最新版本的包到src目录下 无法试下包的多版本控制
Go vendor
存放依赖的副本,解决了多个项目需要同一个package依赖的问题
Go Module
1.目标:定义版本规则和管理项目依赖关系 通过go.mod文件管理以来版本 通过go get/go mod指令工具管理依赖包
2.依赖管理三要素
(1)配置文件,描述依赖 go.mod {MINOR}.${PATCH} v1.17.12 编译时,满足本次构建的最低的兼容版本
(2)中心仓库管理依赖库 Proxy
GOPROXY="proxy1.cn,https://proxy2.cn,…"
Proxy1->Proxy2->direct
(3)本地工具 go get/mod
7.心得体会
今天又学到了很多知识,理解了"lock"在高并发中的巨大贡献,以及waitgroup在高并发中的合理使用。希望在日后的学习中,能够熟练运用本节知识,去处理类似于“生产——消费”以及“排队——买票”等问题。