当前位置: 首页 > news >正文

Golang学习笔记:标准库sync包

在Go语言中,sync包提供了用于处理并发常使用的多种同步原语,以下是sync中核心,也是常用的组件:

  • Sync.Mutex 互斥锁,用于保护临界区,防止多个goroutinue访问同一资源。
  • Sync.RWMutex 读写锁,允许多个协程读取共享资源,而写独占。
  • sync.WaitGroup 等待一组协程执行完成。
  • sync.Map 一个并发安全的map,适合map的并发读写场景。 参考
  • sync.Pool 对象池,管理重复使用的对象,减少内存分配和垃圾回收压力。参考
  • sync.Cond 条件变量,用于在协程之间协调事件发生的顺序。参考
  • sync.Once 用于单例对象的创建。参考

Sync.Mutex

互斥锁,用于在并发环境中多个协程修改共享数据,通过Lock获取锁,Unlock释放锁。

package mainimport ("fmt""sync""time"
)var (mu    sync.Mutexcount int
)func main() {wg := new(sync.WaitGroup)for i := 1; i <= 10; i++ {wg.Add(1)go func(i int) {defer wg.Done()increment()}(i)}wg.Wait()fmt.Println("count: ", count)
}func increment() {for i := 1; i <= 5; i++ {mu.Lock()count++mu.Unlock()time.Sleep(100 * time.Millisecond)}
}

实现原理

参考
sync.Mutex的结构体:

type Mutex struct {state int32sema  uint32
}

state表示当前锁的状态,sema用于控制锁状态的信号量,当持有该锁的协程释放锁后,通过sema来唤醒阻塞等待获取锁的协程。

互斥锁的两种模式

Mutex有两种模式,正常模式和饥饿模式,
正常模式下,所有阻塞在等待队列中的goroutine会按顺序进行锁获取,当唤醒一个等待队列中的goroutine时,此goroutine并不会直接获取到锁,而是会和新请求锁的goroutine竞争。 通常新请求锁的goroutine更容易获取锁,这是因为新请求锁的goroutine正在占用cpu片执行,大概率可以直接执行到获取到锁的逻辑。

饥饿模式下, 新请求锁的goroutine不会进行锁获取,而是加入到队列尾部阻塞等待获取锁。

饥饿模式的触发条件

  • 当一个goroutine等待锁的时间超过1ms时,互斥锁会切换到饥饿模式.

饥饿模式的取消条件

  • 当获取到锁的这个goroutine是等待锁队列中的最后一个goroutine,互斥锁会切换到正常模式
  • 当获取到锁的这个goroutine的等待时间在1ms之内,互斥锁会切换到正常模式

总结

sync.Mutex通过state表示锁的状态,但锁被释放后,通过信号量唤醒阻塞等待获取锁的协程。另外锁有两种模式:正常模式和饥饿模式。

sync.RWMutex

读写锁,是互斥锁的一个改进版,允许多个读者同时访问数据但只允许一个写者,用RLock获取读锁,RUnlock释放读锁;Lock和Unlock分别获取锁和释放锁;

package mainimport ("fmt""sync""time"
)var (mu   sync.RWMutexdata = make(map[string]string)
)func main() {wg := new(sync.WaitGroup)for i := 0; i < 4; i++ {wg.Add(1)go func(i int) {defer wg.Done()readData(fmt.Sprintf("key-%d", i))}(i)}go func() {writeData("testKey", "testValue")}()wg.Wait()fmt.Printf("final data: %+v\n", data)
}func readData(key string) {mu.RLock()defer mu.RUnlock()fmt.Printf("read cache key: %s; value: %s\n", key, data[key])time.Sleep(100 * time.Millisecond)
}func writeData(key string, value string) {mu.Lock()defer mu.Unlock()data[key] = valuetime.Sleep(100 * time.Millisecond)
}

原理

偷个懒 参考

总结

sync.RWMutex是互斥锁的一个改进版,试用于例如缓存、配置信息等读多写少的场景中。特点是:读写互阻塞,读读不阻塞。

sync.WaitGroup

sync.WaitGroup是go标准库sync提供的同步原语,用于等待一组协程执行完成。他的主要作用是等待所有协程执行完成之后做后续动作,避免主程序过早退出。

源码解读

type WaitGroup struct {noCopy noCopy  //避免复制state atomic.Uint64 // high 32 bits are counter, low 32 bits are waiter count. 高32位表示counter的数据(及未完成的协程数量),低32位表示等待者(waiter)的数量sema  uint32 //信号量, 用于阻塞 / 唤醒 waiter
}

使用方法

  • Add方法
    Add方法的主要作用是管理计数器counter,并在counter为0时,唤醒waiter。

  • Done方法
    Done方法主要作用是标记一个协程已经执行完成, 减少counter值。

  • Wait方法
    Wait方法用于等待counter的值为0,当counter为0时会被runtime_Semrelease唤醒,执行后续操作。

总结

sync.WaitGroup是通过counter的增减追踪协程的完成状态,通过信号量实现阻塞和唤醒。这样能够保证所有协程完成后,主程序才会向下运行。

http://www.dtcms.com/a/406475.html

相关文章:

  • 【Git】Git 简介及基本操作
  • 网站模版怎么做wordpress 图片 二级域名
  • 点击EDGE浏览器下载的PDF文件总在EDGE中打开
  • 用MATLAB画一只可爱的小熊
  • Matlab通过GUI实现点云的半径滤波(Radius Outlier Removal)
  • 基于MATLAB的8QAM调制解调仿真与BER性能分析
  • 2025年AI证书报考指南:CAIP/华为/谷歌认证
  • 合肥营销型网站建设开发河南城源建设工程有限公司网站
  • 若依 springboot websocket
  • 开源 C# 快速开发(三)复杂控件
  • Visual Studio使用C++配置OpenCV环境,同时添加模板以4.12为例
  • JUnit 4 + Spring Boot 测试依赖
  • HTML应用指南:利用POST请求获取全国索尼体验型零售店位置信息
  • html网站源码 html网页模板下载
  • 做网站接广告了解基本的php wordpress
  • 房地产手机网站模板网站推广公司ihanshi
  • 推荐一个网站
  • 前端可视化第一章:PixiJS入门指南
  • 时间序列分析新视角:单变量预训练 多变量微调
  • coqui-ai/TTS 安装
  • linux命令dd单刷镜像文件
  • 奔驰押注中国AI,国产大模型上车
  • 笔记(C++篇)—— Day 11
  • Cursor推出全新文档中心:甚至提供详细的中文版本
  • 选择合肥网站建设html的基本结构
  • Linux文件系统调用详解:底层操作到高级应用
  • 基于51单片机的供电保护系统
  • 网站建设技术交流制作公司网页价钱
  • 前端Bug实录:为什么表格筛选条件在刷新时神秘消失?
  • 关于做视频网站的一些代码网站备案号是什么样子