这是我参与「第五届青训营 」笔记创作活动的第 4 天
|| 🎶今日笔记🎶 ||
项目笔记:并发编程
- 协程Goroutine
- 通道Channel
- 锁Lock pkg.go.dev/sync
前言
并发并行的区别
并发:多线程程序在一个核的CPU上运行
并行:多线程程序在多个核的CPU上运行
Go可以充分发挥多核优势 高效运行
协程Goroutine
协程:用户态,轻量级线程 栈MB级别
线程:内核态,线程跑多个协程,栈KB级别
线程的创建、切换、停止较大地占用系统资源
协程的创建和调度由Go语言进行完成
通过开启协程快速打印 hello goroutine 案例:
package concurrence
import (
"fmt"
"time"
)
func hello(i int) {
println("hello goroutine : " + fmt.Sprint(i))
}
func GoRoutine() {
for i := 0; i < 5; i++ {
// go关键字作为创建协程的关键字
go func(j int) {
hello(j)
}(i)
}
// 保证子协程运行完前主线程不退出
time.Sleep(time.Second)
}
Channel 通道
创建方式:make(chan 元素类型, [缓冲大小])
通道是用来传递数据的一个数据结构,可以用于两个goroutine之间,通过传递一个指定类型的值来同步运行和通讯。操作符<-用于指定通道的方向,实现发送or接收若未指定方向,则为双向通道
通过两个Channel通道案例:
package concurrence
func CalSquare() {
src := make(chan int)
dest := make(chan int, 3)
go func() {
defer close(src)
for i := 0; i < 15; i++ {
src <- i
}
}()
go func() {
defer close(dest)
for i := range src {
dest <- i * i
}
}()
for i := range dest {
//复杂操作
println(i)
}
}
锁 Lock
若采用共享内存实现通信,则会出现多个Goroutine同时操作一块内存资源的情况,这种情况会发生竞态问题(数据竞态)
如何解决互斥锁解决数据竞争:
互斥锁是一种常用的控制共享资源访问的方法,它能够保证同时只有一个goroutine可以访问共享资源。Go语言中使用sync包的Mutex类型来实现互斥锁。
package concurrence
import (
"sync"
"time"
)
var (
x int64
lock sync.Mutex
)
func addWithLock() {
for i := 0; i < 1000; i++ {
lock.Lock()
x += 1
lock.Unlock()
}
}
func addWithoutLock() {
for i := 0; i < 1000; 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 < 7; i++ {
go addWithLock()
}
time.Sleep(time.Second)
println("WithLock:", x)
}
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()
}
~ End ~