这是我参与「第五届青训营 」伴学笔记创作活动的第 2 天.
基于CSP的并发特性
CSP
CSP(顺序通信进程)。在CSP中,程序是一组中间没有共享状态的平行运行的处理过程,它们之间使用管道进行通信和控制同步。
线程和协程
线程 :内核态,线程跑多个协程,栈MB级别。
协程 :用户态,轻量级线程,栈KB级别
Goroutines
每一个并发的执行单元叫作一个goroutine。 可以简单地把goroutine类比作一个线程。
当一个程序启动时,其主函数即在一个单独的goroutine中运行,我们叫它main goroutine。新的goroutine会用go语句来创建。在语法上,go语句是一个普通的函数或方法调用前加上关键字go。go语句会使其语句中的函数在一个新创建的goroutine中运行。而go语句本身会迅速地完成。
channel
一个channel是一个通信机制,它可以让一个goroutine通过它给另一个goroutine发送值信息。每个channel都有一个特殊的类型,也就是channels可发送数据的类型。一个可以发送int类型数据的channel一般写为chan int。
WaitGroup
实现阻塞
Add()计数器增加
Done()一个协程完成后计数器减一
Wait()阻塞直到等待计数器归0
两种模式:
1.通过通信共享内存
2.通过共享内存实现通信
模式1,通过通信共享内存
开辟的不同的内存运行协程,协程之间使用cahnnel通信
package main
import (
"fmt"
)
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 {
fmt.Println(i)
}
}
func main() {
CalSquare()
//time.Sleep(time.Second)
}
运行结果
模式2.通过共享内存实现通信
不同的协程之间使用同一块内存,通过Lock加锁解决并发安全。
package main
import (
"fmt"
"sync"
"time"
)
var (
x int64
lock sync.Mutex
)
func main() {
myAdd()
}
func myAdd() {
var wg sync.WaitGroup
wg.Add(5)
x = 0
for i := 0; i < 5; i++ {
go func() {
defer wg.Done()
for i := 0; i < 2000; i++ {
lock.Lock()
x += 1
lock.Unlock()
}
}()
}
wg.Wait()
fmt.Println("withLock: ", x)
wg.Add(5)
x = 0
for i := 0; i < 5; i++ {
go func() {
defer wg.Done()
for i := 0; i < 2000; i++ {
x += 1
}
}()
}
wg.Wait()
fmt.Println("whithoutLoc: ", x)
}