这是我参与「第五届青训营 」伴学笔记创作活动的第 2 天
并发vs并行
-
并发:多线程在一个核上运行,一条路上多个时间有不同的车辆汇入
-
并行:多修一条路,每条路上有一辆车在跑,成本大得多
Goroutine(线程vs协程)
- 协程:用户态,轻量级,栈MB级别
- 线程:内核态,线程跑多个协程,栈MB级别 图文解释:
举例:
- go func()就是多协程的使用方法,一次可以创建上万级别
- Sleep函数用来等待协程运行完毕
CSP(通讯共享内存)
- go语言提倡通过通讯共享内存而不是通过共享内存来实现通讯
Channel(通道)
- 创建:通过make(chan 元素类型,[缓冲大小])
- 分为两个类型:1.无缓冲通道 make(chan int)不指定大小 2.有缓冲通道 make(chan int,2)指定大小
package main
import (
"fmt"
)
func main() {
src := make(chan int)
dest := make(chan int, 3)
// 子协程src发送0~9数字
go func() {
defer close(src) // 推迟关闭,当子协程src结束的时候再关闭,减少资源浪费
for i := 0; i < 10; i++ {
src <- i//相当于将i发送给通道src
}
}()
// 子协程dest计算输入数字的平方
go func() {
defer close(dest)//与之前一样,推迟关闭
// 通过 range 关键字来实现遍历读取到的数据
for i := range src {
dest <- (i * i)//将i的平方发送给dest通道
}
}()
// 主协程输出最后的答案
// 这里可以暂时认为子协程需要使用匿名函数
for i := range dest {
// 因为主协程可能会有更多的复杂操作,比较耗时,所以用带缓冲的通道可以避免问题
fmt.Println(i)
}
}
并发安全Lock
- 主要是
lock.Lock()
x+=1
lock.Unlock()
部分可以通过lock锁的方式来实现并发安全
WaitGroup
- Add(n)计数器+n
- Done()计数器-1
- Wait()阻塞到计数器为0
- 通过上述操作来代替sleep操作,让并发操作更加安全