golang中的sync包
目录
在 Go 语言中,sync
包提供了用于处理并发控制的基本原语,它是 Go 语言标准库的一部分,主要用于解决多线程或多协程环境下的数据同步问题。以下是 sync
包中一些核心类型和组件的简要说明:
-
sync.Mutex:
- Mutex 是 Mutual Exclusion(互斥锁)的缩写,是一个简单的互斥锁类型,用于保护在并发环境中可能会同时被多个协程修改的数据。通过调用
Lock()
获取锁来阻止其他协程访问受保护的代码段,完成操作后通过Unlock()
释放锁。
- Mutex 是 Mutual Exclusion(互斥锁)的缩写,是一个简单的互斥锁类型,用于保护在并发环境中可能会同时被多个协程修改的数据。通过调用
-
sync.RWMutex:
- RWMutex 是 Read-Write Mutex(读写互斥锁),比 Mutex 提供了更多的灵活性,它可以支持多个读取者同时访问但只允许一个写入者。有
RLock()
用于获取读锁和RUnlock()
用于释放读锁;Lock()
和Unlock()
则用于获取和释放写锁。
- RWMutex 是 Read-Write Mutex(读写互斥锁),比 Mutex 提供了更多的灵活性,它可以支持多个读取者同时访问但只允许一个写入者。有
-
sync.Once:
- Once 类型保证某个动作在其生命周期内仅被执行一次,这对于初始化或其他只需要执行一次的操作非常有用。它有一个方法
Do(func())
,该函数接收一个无参数无返回值的函数作为参数,确保这个函数在整个程序运行期间只被执行一次。
- Once 类型保证某个动作在其生命周期内仅被执行一次,这对于初始化或其他只需要执行一次的操作非常有用。它有一个方法
-
sync.WaitGroup:
- WaitGroup 用于等待一组 goroutine 完成任务。通过
Add(delta int)
增加待完成的任务数量,每个已完成任务的 goroutine 调用Done()
减少任务数,而主线程或者其他等待goroutine可以通过Wait()
阻塞直到所有任务完成。
- WaitGroup 用于等待一组 goroutine 完成任务。通过
-
sync.Map:
- Map 是一个并发安全的映射容器,设计用来在高并发环境下替代普通的 map。它通过内部维护两个映射(read 和 dirty)以及适当的锁机制来优化读写性能。它允许并发读取,同时保证写入操作的安全性。
-
sync.Pool:
- Pool 提供了一种临时对象重用的机制,以减少内存分配的压力。Pool 可以存储并复用任意类型的值,当需要新值时可以从池中获取,不再需要时归还到池中,从而避免频繁地创建和销毁小对象。
-
sync.Cond:
- Cond 实现了条件变量,允许一组 Goroutines 在满足特定条件时相互通知。通过与互斥锁配合使用,Cond 提供了
Broadcast()
、Signal()
用于发送信号唤醒等待的 Goroutine,以及Wait()
方法让当前 Goroutine 在条件不满足时等待。
- Cond 实现了条件变量,允许一组 Goroutines 在满足特定条件时相互通知。通过与互斥锁配合使用,Cond 提供了
总结来说,Go 语言的 sync
包为编写高性能且线程安全的并发代码提供了强大的基础工具集。在实际应用中,开发者可以根据具体需求选择合适的同步原语来控制并发流程。
以下是一些使用 sync
包中不同组件的简单示例:
- 使用
sync.Mutex
的例子:
package main
import (
"fmt"
"sync"
)
var count int
var mutex = &sync.Mutex{}
func increment() {
mutex.Lock()
count++
fmt.Println("Count:", count)
mutex.Unlock()
}
func main() {
var wg sync.WaitGroup
for i := 0; i < 10; i++ {
wg.Add(1)
go func() {
defer wg.Done()
increment()
}()
}
wg.Wait()
}
在这个示例中,我们使用 Mutex
来保护对共享变量 count
的并发访问,防止竞态条件。
- 使用
sync.WaitGroup
的例子:
package main
import (
"fmt"
"sync"
)
func worker(id int, wg *sync.WaitGroup) {
defer wg.Done()
fmt.Printf("Worker %d started\n", id)
// 模拟耗时工作
for i := 0; i < 5; i++ {
fmt.Printf("Worker %d is working...\n", id)
}
fmt.Printf("Worker %d finished\n", id)
}
func main() {
var wg sync.WaitGroup
for i := 1; i <= 3; i++ {
wg.Add(1)
go worker(i, &wg)
}
wg.Wait()
fmt.Println("All workers have finished.")
}
在这个示例中,我们启动了3个worker goroutine,并使用 WaitGroup
确保所有worker完成工作后再结束main函数。
- 使用
sync.Once
的例子,保证初始化只执行一次:
package main
import (
"fmt"
"sync"
)
var once sync.Once
var message string
func setup() {
message = "Hello, World!"
fmt.Println("Setting up the message")
}
func printMessage() {
once.Do(setup)
fmt.Println(message)
}
func main() {
printMessage()
printMessage()
}
在这个示例中,setup
函数只会执行一次,尽管 printMessage
被调用了多次。这是因为 Once.Do
方法确保了传入的函数只执行一次。
Do not communicate by sharing memory; instead, share memory by communicating.
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· .NET10 - 预览版1新功能体验(一)