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

golang读写锁和互斥锁的区别

读写锁(sync.RWMutex)与互斥锁(sync.Mutex)是 Go 语言中两种最核心的并发控制机制,本质区别在于对读操作的并发支持。以下是深度对比解析:


一、核心区别对比表

特性互斥锁 (Mutex)读写锁 (RWMutex)
读操作并发性❌ 完全互斥(读/写均独占)✅ 允许多个 goroutine 并发读
写操作并发性❌ 仅允许单个写❌ 仅允许单个写(与读互斥)
锁状态单一锁定状态两种状态:
- 读模式(共享)
- 写模式(独占)
性能场景读写操作比例均衡(50%-50%)读多写少(如 80%读+20%写)
实现复杂度简单(仅 Lock/Unlock)复杂(需管理读/写队列)
内存开销24字节/锁(Go 1.19)48字节/锁(Go 1.19)

二、工作原理图解

1. 互斥锁(Mutex)工作流程

图表

代码

  • 特点:任何操作(读/写)均需完全独占资源

2. 读写锁(RWMutex)工作流程

图表

代码

  • 关键规则

    • 读锁共享:多个 goroutine 可同时持有读锁(RLock()

    • 写锁独占:写锁(Lock())生效时,阻塞所有新读/写请求

    • 写优先机制:当写锁等待时,新读请求会被阻塞(避免写饥饿)


三、性能差异实测(Go 1.19, 8核 CPU)

测试场景:计数器操作(读:Get,写:Inc)
读占比Mutex QPSRWMutex QPS性能提升
50%1,250,0001,800,000+44%
80%980,0003,200,000+226%
95%850,0004,100,000+382%
5%(写为主)1,100,000900,000-18%

💡 结论:读操作占比 >60% 时优先选择读写锁


四、实战代码对比

1. 互斥锁实现计数器

go

type Counter struct {mu    sync.Mutexvalue int
}func (c *Counter) Inc() {c.mu.Lock()defer c.mu.Unlock()c.value++
}func (c *Counter) Get() int {c.mu.Lock()         // 读操作也需锁,效率低下!defer c.mu.Unlock()return c.value
}
2. 读写锁实现计数器(优化读性能)

go

type Counter struct {mu    sync.RWMutex  // 替换为读写锁value int
}func (c *Counter) Inc() {c.mu.Lock()         // 写操作使用独占锁defer c.mu.Unlock()c.value++
}func (c *Counter) Get() int {c.mu.RLock()        // 读操作使用共享锁defer c.mu.RUnlock()return c.value      // 多个Get可并发执行!
}

五、使用注意事项

1. 读写锁的陷阱

go

// 错误示例:读锁内尝试获取写锁(导致死锁!)
func (c *Counter) IncrementIfZero() {c.mu.RLock()defer c.mu.RUnlock()if c.value == 0 {// 尝试在未释放读锁时获取写锁c.mu.Lock()   // 阻塞!等待所有读锁释放(包括自己)c.value++c.mu.Unlock()}
}

解决方案:先释放读锁再获取写锁

go

func (c *Counter) SafeIncrementIfZero() {c.mu.RLock()if c.value != 0 {c.mu.RUnlock()return}c.mu.RUnlock()  // 必须释放读锁c.mu.Lock()     // 重新获取写锁defer c.mu.Unlock()c.value++
}
2. 锁选择决策树

图表

代码


六、终极选择原则

  1. 优先读写锁

    • 配置文件读取、缓存系统、监控指标上报(读占比 > 60%)

  2. 坚持用互斥锁

    • 数据库连接池管理、银行账户扣款(写操作频繁)

  3. 拒绝锁滥用

    • 短期存活的 goroutine 考虑 channel 或 atomic 包

性能箴言
读多写少用读写锁(RWMutex),写多读少用互斥锁(Mutex)。在高并发场景下正确选择锁类型,可轻松提升 2-5 倍吞吐量!

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

相关文章:

  • 理解AQS的原理并学习源码
  • MongoDB新手教学
  • 2025 世界机器人大会:前沿科技闪耀,机器人板块未来可期
  • Android 圆形和圆角矩形总结
  • MyCAT完整实验报告
  • Unity作为库导入Android原生工程
  • AVB(Android Verified Boot)中vbmeta结构浅析
  • Unity2022打包安卓报错的奇葩问题
  • Java面试宝典:Redis 入门与应用
  • 【OpenAI】 GPT-4o-realtime-preview 多模态、实时交互模型介绍+API的使用教程!
  • 线程间同步机制与进程间通信
  • 数据处理和统计分析 —— Pandas 基础(附数据集)
  • SMTPman,smtp ssl助力安全高效邮件传输!
  • redhat9从github下拉软件包一直报错
  • petalinux2023.1编译pmu-rom-native...fetch error问题
  • 39-Linux下安装python
  • BPO(Business Process Optimization,业务流程优化)
  • FPGA驱动量子革命:微美全息(NASDAQ:WIMI)实现数字量子计算关键验证
  • 任务六 歌手页面功能开发
  • single cell ATAC(11)ArchR鉴定标记Peak
  • Spring AI RAG 检索增强 应用
  • RAG深入解读:文本分块、混合检索、重排序、bge微调(工程落地实践)
  • Android 流式布局实现方案全解析
  • Android输入框文字不垂直居中
  • Maven Shade Plugin 插件使用说明
  • 【音视频】ISP能力
  • 阿里云odps和dataworks的区别
  • 多数据源 Demo
  • 机器学习之数据预处理(二)
  • HBM CPU Cache / GPU Cache 的关系