超越传统:Go Sync 包的六大秘籍,并发编程从此不纠结!
2024-01-02 20:51:11
超越传统:Go Sync 包的六大秘籍,并发编程从此不纠结!
并发编程是现代软件开发中不可或缺的一部分,但它同时也充满了挑战。在 Go 语言中,sync 包为我们提供了丰富的并发编程工具,让我们能够轻松应对并发编程中的各种难题。本文将深入探讨 sync 包中的六个关键概念:Mutex、RWMutex、WaitGroup、Cond、Once 和 Atomic,并辅以代码示例,让您全面理解其运作机制。掌握这些概念,您将如鱼得水,纵横并发编程之海。
一、Mutex:互斥锁的利剑,守护共享资源的安全
Mutex,即互斥锁,是并发编程中的基本工具,用于保护共享资源不被多个 goroutine 同时访问。它就像一把利剑,在共享资源的入口处站岗放哨,确保只有一个 goroutine 能够进入。
import (
"fmt"
"sync"
)
var (
mu sync.Mutex
count int
)
func increment() {
mu.Lock()
count++
mu.Unlock()
}
func main() {
for i := 0; i < 100; i++ {
go increment()
}
fmt.Println(count)
}
二、RWMutex:读写锁的妙笔,平衡共享资源的读写
RWMutex,即读写锁,是 Mutex 的升级版,它允许多个 goroutine 同时读取共享资源,但只能有一个 goroutine 写入共享资源。这就像一把妙笔,在共享资源的读写之间取得了微妙的平衡。
import (
"fmt"
"sync"
)
var (
rmu sync.RWMutex
count int
)
func read() {
rmu.RLock()
fmt.Println(count)
rmu.RUnlock()
}
func write() {
rmu.Lock()
count++
rmu.Unlock()
}
func main() {
for i := 0; i < 100; i++ {
go read()
}
for i := 0; i < 10; i++ {
go write()
}
fmt.Println(count)
}
三、WaitGroup:等待协程的号角,协调协程的同步
WaitGroup,即等待组,用于协调多个 goroutine 的同步。它就像一个号角,当所有 goroutine 都执行完毕时,它会发出信号,通知等待的 goroutine 继续执行。
import (
"fmt"
"sync"
)
var (
wg sync.WaitGroup
)
func hello(i int) {
defer wg.Done()
fmt.Println("Hello", i)
}
func main() {
for i := 0; i < 10; i++ {
wg.Add(1)
go hello(i)
}
wg.Wait()
fmt.Println("All goroutines finished!")
}
四、Cond:条件变量的哨兵,唤醒沉睡的协程
Cond,即条件变量,用于在满足某些条件时唤醒正在等待的 goroutine。它就像一个哨兵,当条件满足时,它会发出信号,唤醒沉睡的 goroutine,让它们继续执行。
import (
"fmt"
"sync"
)
var (
mu sync.Mutex
cond sync.Cond
data = make([]int, 0)
)
func producer() {
for i := 0; i < 10; i++ {
mu.Lock()
data = append(data, i)
mu.Unlock()
cond.Signal()
}
}
func consumer() {
mu.Lock()
for len(data) == 0 {
cond.Wait(&mu)
}
fmt.Println(data[0])
data = data[1:]
mu.Unlock()
}
func main() {
go producer()
go consumer()
var input string
fmt.Scanln(&input)
}
五、Once:一次性的执行,确保任务的唯一性
Once,即一次性执行,用于确保某个任务只执行一次。它就像一个开关,一旦被打开,就无法再关闭。这对于需要确保任务只执行一次的场景非常有用。
import (
"fmt"
"sync"
)
var (
once sync.Once
initialized = false
)
func initOnce() {
once.Do(func() {
initialized = true
})
}
func main() {
for i := 0; i < 10; i++ {
go initOnce()
}
fmt.Println(initialized)
}
六、Atomic:原子操作的利器,保障数据的安全
Atomic,即原子操作,用于确保多个 goroutine 对共享变量的修改是原子的,即不会被中断。它就像一把利器,能够保障数据的安全。
import (
"fmt"
"sync/atomic"
)
var count int32
func increment() {
atomic.AddInt32(&count, 1)
}
func main() {
for i := 0; i < 100; i++ {
go increment()
}
fmt.Println(count)
}