GO语言中的悲观锁与乐观锁

devtools/2025/2/19 9:59:14/

乐观锁和悲观锁是两种不同的并发控制策略,它们的主要区别在于对资源冲突的处理方式不同。每种锁都有适用的场景,根据实际情况选择使用哪种锁,可以帮助提高系统的并发性能和效率。

1. 悲观锁(Pessimistic Locking)

悲观锁的核心思想是“总是假设会发生冲突”,因此每次访问共享资源时都会主动加锁。这样,其他线程或者协程在获取锁之前会被阻塞,直到锁被释放。

特点:
  • 加锁:在操作数据之前,线程总是先加锁。这样可以确保在执行操作期间,其他线程无法访问该资源。
  • 阻塞:如果一个线程已经持有锁,其他线程需要等待,直到锁被释放才能继续执行。
  • 适用场景:适用于高竞争场景,数据冲突频繁发生时(如银行账户系统的资金操作),悲观锁可以避免并发问题。
示例(悲观锁):

假设我们使用数据库中的悲观锁来实现这一机制:

SELECT * FROM account WHERE account_id = 1 FOR UPDATE;

上面这条SQL语句会锁定查询到的那一行,直到事务完成才会释放锁。

Go中的悲观锁(Mutex)示例:
package mainimport ("fmt""sync"
)var mu sync.Mutexvar counter intfunc increment() {mu.Lock()         // 获取锁counter++mu.Unlock()       // 释放锁
}func main() {var wg sync.WaitGroupfor i := 0; i < 10; i++ {wg.Add(1)go func() {defer wg.Done()increment()}()}wg.Wait()fmt.Println("Counter:", counter)
}

2. 乐观锁(Optimistic Locking)

乐观锁的核心思想是“假设不会发生冲突”,因此在访问共享资源时不加锁,而是在提交数据时进行验证。具体来说,乐观锁通常通过版本号或时间戳来检测数据是否发生了变化,如果数据发生变化(即冲突),则会回滚操作或重试。

特点:
  • 无锁操作:在操作数据时不加锁,认为并发冲突的几率较低,因此可以提高系统的性能。
  • 冲突检测:当线程或事务尝试提交修改时,检查资源是否被其他线程修改过。如果没有修改,提交操作;如果已修改,则回滚或重试。
  • 适用场景:适用于冲突较少的情况,例如在线商城的商品浏览,多个用户同时查看商品信息时冲突的概率很低,可以使用乐观锁。
乐观锁的实现方式:
  1. 版本号控制:每次修改数据时,都会更新版本号,提交时通过版本号检查是否发生冲突。
  2. 时间戳控制:每次修改数据时,都会更新数据的时间戳,提交时通过时间戳检查数据是否已经被修改。
Go中的乐观锁(版本号)示例:
package mainimport ("fmt""sync"
)type Account struct {balance intversion intmu      sync.Mutex
}func (a *Account) Deposit(amount int) bool {a.mu.Lock()defer a.mu.Unlock()currentVersion := a.versiona.balance += amounta.version++  // 增加版本号// 假设提交操作时,检查版本号是否一致return currentVersion == a.version-1
}func main() {acc := &Account{balance: 1000, version: 0}var wg sync.WaitGroupfor i := 0; i < 10; i++ {wg.Add(1)go func() {defer wg.Done()success := acc.Deposit(100)if success {fmt.Println("Deposit successful!")} else {fmt.Println("Version conflict occurred!")}}()}wg.Wait()fmt.Println("Final balance:", acc.balance)
}

3. 悲观锁与乐观锁的选择

选择依据
  • 资源冲突的概率:如果多个线程或事务频繁修改同一资源,使用悲观锁较为合适,因为悲观锁可以防止并发写冲突。反之,如果冲突的概率较低,可以使用乐观锁来提高效率。
  • 性能要求:悲观锁由于加锁和阻塞操作,可能会导致性能下降。而乐观锁在没有冲突时无需加锁,能够提供更高的并发性能。
  • 系统的复杂度:乐观锁的实现通常比悲观锁复杂,因为它涉及冲突检测和回滚机制,而悲观锁相对简单。
总结
  • 悲观锁:适用于冲突较多的高竞争场景,确保数据安全性,但可能会影响系统性能。
  • 乐观锁:适用于冲突较少的低竞争场景,可以提供较高的并发性能,但需要额外的冲突检测和回滚机制。

http://www.ppmy.cn/devtools/159266.html

相关文章

DevOps工具链概述

1. DevOps工具链概述 1.1 DevOps工具链的定义 DevOps工具链是支持DevOps实践的一系列工具的集合&#xff0c;这些工具覆盖了软件开发的整个生命周期&#xff0c;包括需求管理、开发、测试、部署和运维等各个环节。它旨在通过工具的集成和自动化&#xff0c;打破开发与运维之间…

打破AI黑盒,拥抱开源力量:基于openGauss+DeepSeek的本地知识库,打造你的专属AI助手!

引言&#xff1a;什么是RAG和LLM&#xff1f; LLM (Large Language Model&#xff0c;大语言模型): 就像 ChatGPT 这样的 AI 模型&#xff0c;拥有强大的语言理解和生成能力&#xff0c;但它们的知识局限于训练数据&#xff0c;且可能产生“幻觉”&#xff08;即生成不准确的信…

kron积计算mask类别矩阵

文章目录 1. 生成类别矩阵如下2. pytorch 代码3. 循环移动矩阵 1. 生成类别矩阵如下 2. pytorch 代码 import torch import torch.nn as nn import torch.nn.functional as Ftorch.set_printoptions(precision3, sci_modeFalse)if __name__ "__main__":run_code 0…

rustdesk远程桌面自建服务器

首先&#xff0c;我这里用到的是阿里云服务器 centos7版本&#xff0c;win版客户端。 准备工作 centos7 服务器端文件&#xff1a; https://github.com/rustdesk/rustdesk-server/releases/download/1.1.11-1/rustdesk-server-linux-amd64.zip win版客户端安装包&#xff1…

P10452 货仓选址

链接&#xff1a;P10452 货仓选址 - 洛谷 题目描述 在一条数轴上有 N 家商店&#xff0c;它们的坐标分别为 A1​∼AN​。 现在需要在数轴上建立一家货仓&#xff0c;每天清晨&#xff0c;从货仓到每家商店都要运送一车商品。 为了提高效率&#xff0c;求把货仓建在何处&…

游戏引擎学习第101天

回顾当前情况 昨天的进度基本上完成了所有内容&#xff0c;但我们还没有进行调试。虽然我们在运行时做的事情大致上是对的&#xff0c;但还是存在一些可能或者确定的bug。正如昨天最后提到的&#xff0c;既然现在时间晚了&#xff0c;就不太适合开始调试&#xff0c;所以今天我…

C# windowForms 的DataGridView控件的使用

C# Windows Forms DataGridView 控件使用详解 DataGridView 是 Windows Forms 中用于显示和编辑表格数据的核心控件。它支持高度自定义的列类型、数据绑定、事件处理和丰富的样式配置。以下是其详细使用方法。 目录 基础使用 数据绑定 列类型与自定义

PostgreSQL技术内幕25:时序数据库插件TimescaleDB

文章目录 0.简介1.基础知识1.1 背景1.2 概念1.3 特点 2.TimescaleDB2.1 安装使用2.1 文件结构2.2 原理2.2.1 整体结构2.2.2 超表2.2.3 自动分区2.2.4 数据写入与查询优化2.2.5 数据保留策略2.2.6 更多特性 0.简介 现今时序数据库的应用场景十分广泛&#xff0c;其通过保留时间…