python中的原子操作简介

深入理解Python中的原子操作

在现代编程中,多线程是提高程序执行效率的常用技术。然而,当多个线程并发执行时,如何确保数据的一致性和操作的正确性成为了一个关键问题。原子操作(Atomic Operation)便是解决这一问题的重要概念。本文将详细解释什么是原子操作,并通过具体示例帮助读者更好地理解这一概念。同时,我们还将探讨与原子操作相关的其他技术,如线程安全、死锁(Deadlock)以及Python中的其他同步机制。

什么是原子操作?

原子操作是指一个不可分割的操作,即这个操作在执行的过程中不会被其他操作打断或干扰。在计算机科学中,原子性(Atomicity)意味着操作要么全部完成,要么全部不完成,没有中间状态。在多线程编程中,原子操作确保了在执行该操作时,其他线程无法访问或修改共享数据,从而避免了竞争条件(Race Condition)和数据不一致问题。

Python中的原子操作

在Python中,某些操作是原子的,这些操作通常包括对简单数据类型(如整数和浮点数)的基本运算和对单个对象属性或列表元素的访问。需要注意的是,本文讨论的是CPython解释器,因为不同的Python解释器(如PyPy、Jython等)可能对原子操作有不同的实现。

整数和浮点数的简单操作

在CPython中,对简单的整数和浮点数的操作,如加减乘除,是原子的。例如:

x = 1
x += 1  # 这个操作在CPython中是原子的

上面的代码中,x += 1是一个原子操作,因为在执行这个操作时,不会有其他线程插入或打断。

单个属性访问和赋值

读取和写入对象的单个属性也是原子的。例如:

class Counter:def __init__(self):self.count = 0counter = Counter()
counter.count += 1  # 这个操作在CPython中是原子的

在上面的代码中,counter.count += 1是一个原子操作,因为对单个属性的读取和写入不会被其他线程干扰。

单个列表元素的访问和赋值

读取和写入列表的单个元素也是原子的。例如:

my_list = [1, 2, 3]
my_list[0] = 4  # 这个操作在CPython中是原子的

在上面的代码中,my_list[0] = 4是一个原子操作,因为对单个列表元素的访问和赋值不会被其他线程干扰。

需要注意的地方

尽管某些操作在CPython中是原子的,但并不是所有的操作都是原子的。对于复合数据结构的操作(如列表、字典的多个元素访问或修改),通常不是原子的。这种情况下,需要使用锁(Lock)来确保操作的原子性。

使用锁确保原子性

锁是一种用于控制多个线程对共享资源的访问的同步机制。通过锁,可以确保某些代码块在任意时刻只能由一个线程执行,从而实现操作的原子性。下面是一个简单的示例,演示如何使用锁来确保操作的原子性:

import threadingclass Counter:def __init__(self):self.count = 0self.lock = threading.Lock()def increment(self):with self.lock:self.count += 1  # 在锁的保护下,这个操作是原子的counter = Counter()def worker():for _ in range(1000):counter.increment()threads = []
for _ in range(10):thread = threading.Thread(target=worker)thread.start()threads.append(thread)for thread in threads:thread.join()print(counter.count)  # 结果应该是10000

在这个例子中,increment方法在加锁的情况下执行self.count += 1操作,从而确保该操作是原子的,不会被其他线程打断。

线程安全和其他同步机制

除了锁,Python还提供了其他几种用于确保线程安全的同步机制,如条件变量(Condition Variable)、信号量(Semaphore)和事件(Event)。

条件变量

条件变量用于在线程之间进行复杂的同步,常用于生产者-消费者问题。例如:

import threadingcondition = threading.Condition()
queue = []def producer():with condition:queue.append(1)condition.notify()  # 通知消费者def consumer():with condition:while not queue:condition.wait()  # 等待生产者item = queue.pop(0)producer_thread = threading.Thread(target=producer)
consumer_thread = threading.Thread(target=consumer)
producer_thread.start()
consumer_thread.start()
producer_thread.join()
consumer_thread.join()

信号量

信号量用于控制对共享资源的访问,如限制同时访问某资源的线程数量。例如:

import threadingsemaphore = threading.Semaphore(3)def worker():with semaphore:print("Accessing shared resource")threads = []
for _ in range(5):thread = threading.Thread(target=worker)thread.start()threads.append(thread)for thread in threads:thread.join()

事件

事件用于线程间通信,使一个线程等待另一个线程的事件发生。例如:

import threadingevent = threading.Event()def setter():event.set()  # 触发事件def waiter():event.wait()  # 等待事件触发print("Event triggered")setter_thread = threading.Thread(target=setter)
waiter_thread = threading.Thread(target=waiter)
waiter_thread.start()
setter_thread.start()
setter_thread.join()
waiter_thread.join()

死锁及其预防

在多线程编程中,死锁是一个常见问题,指两个或多个线程因互相等待对方释放资源而陷入无限等待的状态。为了预防死锁,可以遵循以下策略:

  1. 资源分配顺序:确保所有线程按照相同的顺序请求资源。
  2. 尝试锁(Try Lock):使用尝试获取锁的方法,如果无法获取则放弃,以避免无限等待。
  3. 超时机制:为锁设置超时时间,超过时间则释放锁并采取相应措施。

预防死锁示例

使用尝试锁预防死锁的示例:

import threadinglock1 = threading.Lock()
lock2 = threading.Lock()def worker1():while True:if lock1.acquire(timeout=1):if lock2.acquire(timeout=1):print("Worker1 acquired both locks")lock2.release()lock1.release()breakdef worker2():while True:if lock2.acquire(timeout=1):if lock1.acquire(timeout=1):print("Worker2 acquired both locks")lock1.release()lock2.release()breakthread1 = threading.Thread(target=worker1)
thread2 = threading.Thread(target=worker2)
thread1.start()
thread2.start()
thread1.join()
thread2.join()

总结

原子操作在多线程编程中是确保数据一致性和避免竞争条件的重要概念。尽管Python中某些简单的操作是原子的,但对于更复杂的操作,通常需要使用锁等同步机制来确保原子性。除此之外,理解线程安全、同步机制和死锁预防,对于编写健壮的多线程程序至关重要。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/41855.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

责任链模式(大话设计模式)C/C++版本

责任链模式 C #include <iostream> #include <memory>using namespace std; // 请求类 struct Request {std::string requestType; // 请求类型int number; // 该请求类型的数量std::string requestContent; // 请求内容 };// 抽象经理类 clas…

MySQL学习记录 —— 십칠 CentOS7.9环境下的MySQL8.4 安装和配置

文章目录 1、安装和配置2、MySQL 包位置3、主要程序介绍 本篇开始在之前mysql博客的基础上继续延伸&#xff0c;适合有一定基础的mysql使用者阅读 环境 &#xff1a;CentOS 7.9 root 用户&#xff0c;MySQL 8.4 1、安装和配置 看一下当前系统版本 cat /etc/redhat-release应当…

前端重点之:Vue+websocket通信详细用法和websocket心跳机制的使用,websocket断开实时监测,websocket实时通信

今年年初找工作,好多gou面试官总喜欢问关于websocket通信的使用方式,此次又用到了,在此做个总结:主要包含websocket的具体使用方法,和重点:(心跳机制的使用),就是主要是前端实时监测websocket是否有断连和数据的处理 在前端开发中,WebSocket 是一种常见的技术,用于…

浅谈序列化及文本格式

序列化及文本格式 需求背景 软件项目在开发过程中&#xff0c;将大量初始化配置项在一定程度上保存在配置文件中。肯定有很多人有疑问&#xff0c;为什么不将这些信息放在软件内存中。开机时与用户交互进行确认&#xff1f;这肯定是一个好想法&#xff0c;但是如果配置太多或…

众所周知沃尔玛1P是怎么运营?

​​沃尔玛的1P模式&#xff0c;即第一方供应商模式&#xff0c;是其独特的采购策略。在这种模式下&#xff0c;供应商先将商品卖给沃尔玛&#xff0c;由沃尔玛负责库存管理和销售。沃尔玛通过强大的采购和物流能力控制库存&#xff0c;确保商品品质&#xff0c;为客户提供更加…

FPGA问题

fpga 问题 第一道坎&#xff0c;安装软件&#xff1b;没有注册&#xff0c;无法产生sop文件&#xff0c;无法下载 没有相应的库的quartus ii版本&#xff0c;需要另下载 第二道坎&#xff0c;模拟器的下载&#xff0c;安装&#xff1b; 第三道&#xff0c;verilog 语法&#x…

deepspeed huggingface传入参数 optimizer和lr_scheduler测试

Trainer中 首先&#xff1a; WarmupDecayLR --lr_scheduler_type linear WarmupLR --lr_scheduler_type constant_with_warmup 1 TrainArgument不传lr_scheduler_type、optim&#xff0c;warmup_steps15 ds config文件中定义如下&#xff1a; 注意&#xff1a;如果不在Trai…

LangChain(四)工具调用的底层原理!给大模型按上双手吧!(新手向)

背景 经过前面三篇的内容&#xff0c;我想大家对于大模型的构建、Langchain的优势、Chain的构建有了相当程度的理解&#xff08;虽然只是最简单的示例&#xff0c;但是足够有代表性&#xff09;。 后续Chain的使用将会更加丰富多彩&#xff0c;您会了解Langchain开发的大模型…

14-31 剑和诗人5 - 使用 AirLLM 和分层推理在单个 4GB GPU 上运行 LLama 3 70B

利用分层推理实现大模型语言(LLM) 大型语言模型 (LLM) 领域最近取得了显著进展&#xff0c;LLaMa 3 70B 等模型突破了之前认为可能实现的极限。然而&#xff0c;这些模型的庞大规模给其部署和实际使用带来了巨大挑战&#xff0c;尤其是在资源受限的设备上&#xff0c;例如内存…

怎么压缩pdf文件的大小?减小PDF文件大小的四种方法

怎么压缩pdf文件的大小&#xff1f;文件大小不仅影响传输速度&#xff0c;还可能涉及存储空间的管理。当处理大型PDF文件时&#xff0c;可能会面临电子邮件附件限制或云存储容量不足的问题。此外&#xff0c;过大的文件在浏览和加载时也会导致延迟&#xff0c;影响阅读体验。这…

3款自己电脑就可以运行AI LLM的项目

AnythingLLM、LocalGPT和PrivateGPT都是与大语言模型&#xff08;LLM&#xff09;相关的项目&#xff0c;它们允许用户在本地环境中与文档进行交互&#xff0c;但它们在实现方式和特点上存在一些差异。AnythingLLM使用Pinecone和ChromaDB来处理矢量嵌入&#xff0c;并使用OpenA…

【C语言】return 关键字详解

在C语言中&#xff0c;return是一个关键字&#xff0c;用于从函数中返回值或者结束函数的执行。它是函数的重要组成部分&#xff0c;负责将函数的计算结果返回给调用者&#xff0c;并可以提前终止函数的执行。 主要用途和原理&#xff1a; 返回值给调用者&#xff1a; 当函数执…

mysql数据库创建用户并授权某个库的所有权限

这个就直接上语句吧&#xff01;只是注意要用管理员帐号执行&#xff0c;比如root去执行。 -- 创建新用户&#xff08;替换new_user为您的用户名&#xff0c;password为您的密码&#xff09; CREATE USER new_user% IDENTIFIED BY password; -- 授予权限&#xff08;替换data…

社交媒体数据分析:赋能企业营销策略的利器

在这个数字化时代&#xff0c;社交媒体不仅是品牌与消费者互动的舞台&#xff0c;更是企业洞察市场趋势、优化营销策略的金矿。本文将探讨如何利用社交媒体数据分析赋能企业营销&#xff0c;通过实战案例与技巧分享&#xff0c;揭示这把“利器”如何帮助企业精准定位目标受众、…

【论文阅读】-- Visual Traffic Jam Analysis Based on Trajectory Data

基于轨迹数据的可视化交通拥堵分析 摘要1 引言2 相关工作2.1 交通事件检测2.2 交通可视化2.3 传播图可视化 3 概述3.1 设计要求3.2 输入数据说明3.3 交通拥堵数据模型3.4 工作流程 4 预处理4.1 路网处理4.2 GPS数据清理4.3 地图匹配4.4 道路速度计算4.5 交通拥堵检测4.6 传播图…

架构面试-场景题-单点登录(SSO)怎么实现的

文章目录 概述基于Cookie基于Token(OAuth, JWT)集中式认证服务 (CAS, SAML)分布式Session:轻型目录访问协议&#xff08;LDAP&#xff09;OAuth 2.0/OIDCKerberos 概述 单点登录&#xff08;Single Sign-On&#xff0c;简称SSO&#xff09;是一种身份验证机制&#xff0c;允许…

掌握【Python异常处理】:打造健壮代码的现代编程指南

目录 ​编辑 1. 什么是异常&#xff1f; 知识点 示例 小李的理解 2. 常见的内置异常类型 知识点 示例 小李的理解 3. 异常机制的意义 知识点 示例 小李的理解 4. 如何处理异常 知识点 示例 小李的理解 5. 抛出异常 知识点 示例 小李的理解 6. Python内置…

Springboot整合Jsch-Sftp

背景 开发一个基于jsch的sftp工具类&#xff0c;方便在以后的项目中使用。写代码的过程记录下来&#xff0c;作为备忘录。。。 Maven依赖 springboot依赖 <parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-par…

codeforces 1633A

文章目录 1. 题目链接2. 题目代码正确代码错误代码 3. 题目总结 1. 题目链接 Div. 7 2. 题目代码 正确代码 #include<iostream> using namespace std; int main(){int testCase;cin >> testCase;while(testCase --){int ingeter;cin >> ingeter;if(!(inget…

SpringBoot彩蛋之定制启动画面

写在前面 在日常开发中&#xff0c;我们经常会看到各种各样的启动画面。例如以下几种 ① spring项目启动画面 ② mybatisplus启动画面 ③若依项目启动画面 还有很多各式各样好看的启动画面&#xff0c;那么怎么定制这些启动画面呢&#xff1f; 一、小试牛刀 ① 新建一个Spr…