1.并发 vs 并行
Go语言能够原生实现多线程程序在多个核的CPU上运行(并行),从而实现高并发的操作。
2.协程 vs 线程
Go语言通过
GOROUTINE也就是(Go协程) 实现高并发,协程是一种轻量级的线程,相比开启/关闭线程来说,是非常轻的系统操作,栈只有KB级别。一个线程可以开启多个携程,最后开启上万个携程也不是问题。
通过在函数前面加 go 关键字实现开启协程。例:
go func (<name><type>){
……
}
3.Go协程通信过程** Comunicating Sequential Process (CSP)**
Go语言提倡使用通信共享内存,而不是共享内存实现通信//这里理解可以参考操作系统的相关知识
4.Channel
GoRoutine使用channel通信协调,共享内存
使用
make(chan <type>,<缓冲大小>)生成channel,当<缓冲大小>为0时,则为无缓冲channel,例:
make(chan int) //无缓冲通道
make(chan int,2) //有缓冲通道
例程:
func Calsqure() {
src := make(chan int)
dest :=make(chan int,3)
go func() {//子协程A(生产):发送数字0~9
defer close(src)
for i := 0; I < 10; i++ {
Src <- i //每次循环将i发送到channel src
}
}()
go func() {//子协程B(生产):计算输入数字的平方,带缓冲
defer close(dest)
for i := range src {
dest <- i * i //每次循环将i * i的值发送到channel dest
}
}()
for i := range dest {//主协程M(消费):输出最后的平方数
//复杂操作
println(i)
}
}
Tips:
-
此时,使用chanel保证了并发的安全性。
-
子协程A中使用channel src实现了与子协程B的通信,子协程B中使用channel dest实现了与主协程M的通信。
-
子协程B采用带缓冲的channel的原因是,主协程M的逻辑可能非常复杂,此时生产的速度大于消费的速度,如果不带缓冲,则消费者消费之后,生产者才能继续生产,带缓冲的channel就避免了浪费生产者的生产效率的问题。
- 并发安全:LOCK
//通过共享内存进行通信的方式
-
使用 lock 的数据类型为
sync.Mutex,即生成一个锁的方式为:var Lock sync.Mutex -
使用
<name>.lock()加锁 -
使用
<name>.unlock()解锁
6.WaitGroup:并发下的同步
为了防止主协程在子协程未运行完其中时关闭,Go语言中的sync包中实现了WaitGroup,主要是实现了一个计数器,计数器在开启协程时加+<delta>,协程关闭时减1,而主协程将阻塞到计数器为0的时候。//delta为int类型的整数
例程:
func ManyGoWait() {
var wg sync.WaitGroup //新建了一个名为wg的WaitGroup
wg.Add(5)//计数器的初值为5,即将开启5个协程
for i :=0; i < 5; i++ {
go func(j int) {
defer wg.Done()//方法结束后WaitGroup-1
hello(j)
}(i)
}
wg.Wait()//阻塞主协程
}