python——多线程的共享变量用法

文章目录

    • 多线程共享变量
      • 锁(Locks)示例
      • 事件(Events)示例
      • 条件变量(Condition Variables)示例
      • 队列(Queues)示例
        • 阻塞传输数据
        • 非阻塞传输数据

多线程共享变量

在Python中,如果你有一个变量shared_var_data在多个线线程之间共享,并且你需要确保即使这个数据长时间未变,其他线程也能正常工作,你可以采取以下策略来实现这一目标:

  1. 使用锁(Locks)来同步访问: 当多个线程需要访问共享数据时,使用锁可以防止数据在被一个线程修改时被另一个线程访问,这可以确保数据的一致性。通过锁的机制,即使shared_var_data长时间未变,其他线程在尝试访问这个数据前需要获得锁,从而保证了数据访问的安全性。

  2. 条件变量(Condition Variables): 条件变量用于线程间的同步,可以让一个或多个线程等待某个条件成立。如果你的场景中shared_var_data长时间未变化是一个需要等待改变的条件,那么可以使用条件变量来通知其他线程数据已经更新,或者某个特定条件已经满足。

  3. 事件(Events): 事件是一个简化的线程同步机制,可以用来通知一个或多个等待的线程某个事件已经发生。如果其他线程需要在shared_var_data发生变化后才能继续执行,可以使用事件来实现这种同步。

  4. 使用队列(Queues)来实现生产者消费者模式: 如果shared_var_data的更新是由某些特定的生产者线程负责,而其他消费者线程需要处理这些更新,使用队列可以很好地解耦生产者和消费者,同时还提供了线程安全的数据访问机制。

  5. 定期检查或轮询: 在一些场景下,如果不需要即时响应数据的变化,可以在其他线程中实现定期检查shared_var_data是否发生变化的逻辑,这种方式简单但可能不够高效,因为它可能引入不必要的延迟和CPU资源消耗。

  6. 使用原子操作: 对于简单的数据类型,使用原子操作(如在某些Python实现中的threadingmultiprocessing模块提供的原子类型)可以确保即使在多线程环境中,对共享数据的单个操作也是原子的,这样可以避免使用锁的开销。

选择哪种策略取决于你的具体应用场景、数据共享的复杂度以及对性能的要求。通常,使用锁和条件变量可以提供最大的灵活性和控制,但也可能带来性能开销。在设计多线程程序时,合理选择同步机制是非常重要的,以确保既能保证数据一致性,又能保持高效的执行。

锁(Locks)示例

在多线程编程中,锁(Locks)是一种基本的同步机制,用于防止多个线程同时访问共享资源,从而避免数据竞争和状态不一致的问题。以下是使用Python的threading模块中的Lock来同步多个线程访问共享数据的一个简单示例。

在这个例子中,我们将创建两个线程,它们都试图修改同一个全局变量counter。为了确保每次只有一个线程能修改counter,我们将使用Lock对象来同步对counter的访问。

import threading# 共享资源
counter = 0# 创建一个锁对象
lock = threading.Lock()# 线程工作的函数
def update_counter(name):global counterprint(f"{name}: 准备更新计数器。")# 请求锁lock.acquire()try:print(f"{name}: 已获得锁。")current_counter = counterprint(f"{name}: 当前计数器值为 {current_counter}。")counter = current_counter + 1print(f"{name}: 更新后的计数器值为 {counter}。")finally:# 无论如何都要释放锁lock.release()print(f"{name}: 已释放锁。")# 创建线程
thread1 = threading.Thread(target=update_counter, args=('线程1',))
thread2 = threading.Thread(target=update_counter, args=('线程2',))# 启动线程
thread1.start()
thread2.start()# 等待线程完成
thread1.join()
thread2.join()print(f"最终计数器值为 {counter}。")

这个示例中,我们通过调用lock.acquire()来请求锁,这会阻塞当前线程直到锁被获得。一旦获得锁,线程就可以安全地访问和修改共享资源(在本例中是counter变量)。完成更新后,我们使用finally语句块来确保锁在操作完成后总是会被释放(通过调用lock.release()),这是一种良好的实践,可以避免死锁的发生。

注意,Python的锁还支持with语句,使得代码更简洁,自动管理锁的获取和释放:

with lock:# 修改共享资源

这种方式在实际编程中更加推荐,因为它简化了代码并减少了因忘记释放锁而可能引发的问题。

事件(Events)示例

下面是一个简单的使用事件(threading.Event)的多线程示例。在这个示例中,我们将创建两个线程:一个事件发布者(EventSetter)和一个事件监听者(EventListener)。EventSetter线程将在睡眠一段时间后设置一个事件,而EventListener线程将等待这个事件被设置,一旦事件被设置,它就会继续执行。

import threading
import time# 创建一个事件对象
event = threading.Event()# 事件监听者线程函数
def event_listener():print("EventListener: 等待事件被设置...")event.wait()  # 阻塞,直到事件被设置print("EventListener: 检测到事件被设置,继续执行...")# 事件发布者线程函数
def event_setter():time.sleep(2)  # 模拟耗时操作print("EventSetter: 准备设置事件...")event.set()  # 设置事件print("EventSetter: 事件已被设置。")# 创建线程
listener_thread = threading.Thread(target=event_listener)
setter_thread = threading.Thread(target=event_setter)# 启动线程
listener_thread.start()
setter_thread.start()# 等待线程完成
listener_thread.join()
setter_thread.join()print("主线程: 所有线程已完成执行。")

这个示例展示了如何使用threading.Event来同步两个线程的执行。event.wait()EventListener线程中调用,使该线程阻塞,直到EventSetter线程调用event.set()。一旦事件被设置,event.wait()将不再阻塞,EventListener线程继续执行。这种机制非常适合于需要等待特定条件满足的场景,例如等待一个任务完成或者资源变得可用。

条件变量(Condition Variables)示例

使用条件变量(Condition)的多线程示例通常涉及到生产者-消费者模式,其中生产者线程生成一些数据,消费者线程消费这些数据。条件变量用于同步线程,确保消费者线程在数据准备好之前等待,并且当数据准备好时,生产者线程通知消费者线程。

下面是一个简单的使用threading.Condition的例子,演示了一个生产者线程和一个消费者线程如何通过条件变量来同步操作。

import threading
import time# 创建条件变量
condition = threading.Condition()
# 用于在生产者和消费者之间传递数据的列表
items = []# 生产者线程函数
def producer():with condition:print("生产者: 正在生产项目...")time.sleep(2)  # 模拟耗时的生产过程items.append("产品")  # 生产一个项目并添加到列表中print("生产者: 产品生产完成,通知消费者。")condition.notify()  # 通知消费者产品已准备好# 消费者线程函数
def consumer():with condition:print("消费者: 等待产品...")condition.wait()  # 等待产品被生产item = items.pop()  # 消费产品print(f"消费者: 已消费 {item}。")# 创建线程
producer_thread = threading.Thread(target=producer)
consumer_thread = threading.Thread(target=consumer)# 启动线程
consumer_thread.start()
producer_thread.start()# 等待线程完成
producer_thread.join()
consumer_thread.join()print("主线程: 所有线程已完成执行。")

这个例子中,生产者线程生产一个项目(模拟为字符串"产品"),然后通过条件变量通知消费者线程产品已经准备好。消费者线程在产品准备好之前会在condition.wait()处阻塞,直到收到生产者的通知。一旦收到通知,消费者线程就会继续执行,从列表中取出产品并消费它。使用with condition语句确保了在操作条件变量时自动获得和释放锁,从而简化了代码并提高了安全性。

队列(Queues)示例

下面分别是使用Python的queue.Queue模块实现的阻塞传输数据和非阻塞传输数据的示例。这两个示例展示了生产者-消费者模式,其中生产者线程向队列中添加数据,而消费者线程从队列中取出数据。

阻塞传输数据

在阻塞模式下,如果队列为空,消费者线程将被阻塞,直到队列中有数据可供消费;如果队列已满,生产者线程将被阻塞,直到队列中有空间可用来添加新的数据项。

import threading
import queue
import time# 创建一个队列
data_queue = queue.Queue(maxsize=5)def producer(name):for i in range(5):time.sleep(1)  # 模拟数据生产耗时item = f'产品{i}'data_queue.put(item)  # 阻塞方式添加数据到队列print(f'{name}: 生产了 {item}')print(f'{name}: 完成生产。')def consumer(name):while True:item = data_queue.get()  # 阻塞方式从队列取出数据if item is None:break  # None是结束信号print(f'{name}: 消费了 {item}')data_queue.task_done()  # 表明之前入队的一个任务已经完成print(f'{name}: 完成消费。')# 启动生产者和消费者线程
producer_thread = threading.Thread(target=producer, args=('生产者',))
consumer_thread = threading.Thread(target=consumer, args=('消费者',))producer_thread.start()
consumer_thread.start()# 等待生产者线程结束
producer_thread.join()
# 发送结束信号
data_queue.put(None)
# 等待消费者线程结束
consumer_thread.join()
非阻塞传输数据

在非阻塞模式下,生产者和消费者在队列满或空时不会阻塞,而是会立即抛出异常或执行某些特定的操作。

import threading
import queue
import time# 创建一个队列
data_queue = queue.Queue(maxsize=5)def producer(name):for i in range(5):item = f'产品{i}'try:data_queue.put(item, block=False)  # 非阻塞方式添加数据到队列print(f'{name}: 生产了 {item}')except queue.Full:print(f'{name}: 队列已满,无法立即生产 {item}')time.sleep(1)  # 模拟其他耗时操作print(f'{name}: 完成生产。')def consumer(name):while True:try:item = data_queue.get(block=False)  # 非阻塞方式从队列取出数据print(f'{name}: 消费了 {item}')time.sleep(2)  # 模拟消费耗时except queue.Empty:print(f'{name}: 队列为空,暂时无法消费')break  # 如果队列为空,则结束消费print(f'{name}: 完成消费。')# 启动生产者和消费者线程
producer_thread = threading.Thread(target=producer, args=('生产者',))
consumer_thread = threading.Thread(target=consumer, args=('消费者',))producer_thread.start()
consumer_thread.start()# 等待生产者和消费者线程结束
producer_thread.join()
consumer_thread.join()

在这两个示例中,生产者线程生产数据并将其放入队列中,而消费者线程从队列中取出并消费这些数据。阻塞和非阻塞操作主要体现在对队列操作时的行为差异:阻塞操作会等待直到条件满足(如队列非满或非空),而非阻塞操作在条件不满足时会立即返回或抛出异常。

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

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

相关文章

掌上新闻随心播控,HarmonyOS SDK助力新浪新闻打造精致易用的资讯服务新体验

原生智能是HarmonyOS NEXT的核心亮点之一,依托HarmonyOS SDK丰富全面的开放能力,开发者只需通过几行代码,即可快速实现AI功能。新浪新闻作为鸿蒙原生应用开发的先行者之一,从有声资讯入手,将基于Speech Kit朗读控件上线…

第98讲:MHA高可用集群VIP地址配置与漂移实践

文章目录 1.为甚要给MHA高可用集群配置VIP地址2.配置MHA高可用集群VIP漂移地址2.1.准备MHA VIP地址的脚本2.2.配置MHA指定VIP地址的脚本2.3.手动在主库上配置VIP地址2.4.重启MHA2.5.模拟主库故障观察VIP是否会自动切换 1.为甚要给MHA高可用集群配置VIP地址 当主库发生故障&…

从kafka如何保证数据一致性看通常数据一致性设计

一、前言 在数据库系统中有个概念叫事务,事务的作用是为了保证数据的一致性,意思是要么数据成功,要么数据失败,不存在数据操作了一半的情况,这就是数据的一致性。在很多系统或者组件中,很多场景都需要保证…

【前端工程化面试题目】说说你对 SSG 的理解

注意 ssg 和 ssr 是不同的,具体请参考这篇文章。 SSG 是静态站点生成器(Static Site Generator)的缩写,它是一种用于构建静态网站的工具或框架。静态站点生成器将一组源文件(通常是 Markdown、HTML、CSS、JavaScript 等…

计算机网络——18无连接传输UDP

无连接传输UDP UDP “尽力而为的”服务,报文段可能 丢失送到应用进程的报文段乱序 无连接 UDP发送端和接收端之间没有握手每个UDP报文段都被独立的处理 UDP被用于 流媒体DNSSNMP 在UDP上实现可靠传输 在应用层增加可靠性应用特定的差错格式 UDP:用户…

Positive SSL 证书介绍

Positive SSL 是一种受欢迎的 SSL 证书,提供了卓越的安全性、性价比和品牌信任。以下是对 Positive SSL 在这些方面的简要介绍: 1. 安全性: Positive SSL 证书采用强大的加密技术,确保网站和用户之间的数据传输是安全的。它使用…

turn服务器debug

turn服务器正常能连通的调用堆栈 turn_port.cc AddRequestAuthInfo check 崩溃 有问题的turn msg type是259 request type 是3 用不了的turn 服务器turnmessage type 275

Mybatis源码分析

Mybatis源码分析 第一章、回顾 1. 课程中工具的版本 1. JDK8 2. IDEA2018.3 3. Maven3.5.3 4. MySQL 5.1.48 --> MySQL 5Mybatis 3.4.62. Mybatis开发的简单回顾 1. Mybatis做什么?Mybatis是一个ORM类型框架,解决的数据库访问和操作的问题&#xf…

RH850从0搭建Autosar开发环境【3X】- Davinci Configurator之OS模块配置详解(中)

OS模块配置详解 - 中 一、OS模块配置实操1.1 打开OS Configuration1.2 创建OS Cores1.3 添加系统定时器1.4 添加一个Os Application1.5 添加几个Task1.5.1 添加Init Task1.5.2 添加BSW Task1.5.3 添加APP Task二、中断分布调整与设置中断号2.1 调整中断分布2.2 正确设置中断号2…

OpenCV介绍和使用

一:简介 OpenCV(Open Source Computer Vision Library)是一个开源的计算机视觉和机器学习软件库,广泛应用于图像处理、计算机视觉、机器学习等领域。它包含了大量的函数和工具,可以用于图像读取、显示、处理、特征提取、目标检测等任务。 OpenCV最初是由Intel公司开发的…

Github:分享一款开源的跨平台多功能远程控制和监控工具Spark

目录 1、设备列表及操作列表 2、登录机器 Shell 执行命令 3、桌面远程访问 4、远程设备的进程管理 5、远程设备文件管理 今天要给大家推荐一个开源的跨平台多功能远程控制和监控工具:Spark。 目前该项目处于不维护状态,大家可以自己根据需要进行扩…

代码随想录 Leetcode763. 划分字母区间

题目&#xff1a; 代码(首刷看解析 2024年2月18日&#xff09;&#xff1a; class Solution { public:vector<int> partitionLabels(string s) {int hash[27] {0};for (int i 0; i < s.size(); i) {hash[s[i] - a] i;}vector<int> res;int left 0;int righ…

PyTorch使用Tricks:学习率衰减 !!

文章目录 前言 1、指数衰减 2、固定步长衰减 3、多步长衰减 4、余弦退火衰减 5、自适应学习率衰减 6、自定义函数实现学习率调整&#xff1a;不同层不同的学习率 前言 在训练神经网络时&#xff0c;如果学习率过大&#xff0c;优化算法可能会在最优解附近震荡而无法收敛&#x…

【开源】SpringBoot框架开发智能教学资源库系统

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 数据中心模块2.2 课程档案模块2.3 课程资源模块2.4 课程作业模块2.5 课程评价模块 三、系统设计3.1 用例设计3.2 数据库设计3.2.1 课程档案表3.2.2 课程资源表3.2.3 课程作业表3.2.4 课程评价表 四、系统展示五、核心代…

超级楼梯(动态规划)

#include <iostream> using namespace std; int main (){int n;cin >> n;int f[41];f[1] 0;f[2] 1;f[3] 2;for (int i 4;i < 42;i){f[i] f[i-1] f[i-2];}while (n--){int stair;cin>> stair;cout << f[stair]<<endl;}return 0; }

【ChatIE】论文解读:Zero-Shot Information Extraction via Chatting with ChatGPT

文章目录 介绍ChatIEEntity-Relation Triple Extration (RE)Named Entity Recognition (NER)Event Extraction (EE) 实验结果结论 论文&#xff1a;Zero-Shot Information Extraction via Chatting with ChatGPT 作者&#xff1a;Xiang Wei, Xingyu Cui, Ning Cheng, Xiaobin W…

嵌入式——EEPROM(AT24C02)

目录 一、初识AT24C02 1. 介绍 2. 引脚功能 补&#xff1a; 二、AT24C02组成 1. 存储结构 2. AT24C02通讯地址 3. AT24C02寻址方式 &#xff08;1&#xff09;芯片寻址 &#xff08;2&#xff09;片内子地址寻址 三、AT24C02读写时序 1. 写操作 &#xff08;1&…

数据结构实验之栈与队列八:栈的基本操作

数据结构实验之栈与队列八&#xff1a;栈的基本操作 Description 堆栈是一种基本的数据结构。堆栈具有两种基本操作方式&#xff0c;push 和 pop。push一个值会将其压入栈顶&#xff0c;而 pop 则会将栈顶的值弹出。现在我们就来验证一下堆栈的使用。 Input 首先输入整数t&am…

Linux|centos7下的编译|ffmpeg的二进制安装

Windows版本的ffmpeg&#xff1a; ###注意&#xff0c;高版本可能必须要windows10以及以上才支持&#xff0c;win7估计是用不了的 下载地址&#xff1a;Builds - CODEX FFMPEG gyan.dev 或者这个下载地址&#xff1a;https://github.com/BtbN/FFmpeg-Builds/releases 这两个…

ClickHouse--12-可视化工具操作

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 可视化工具操作1 tabixhttp://ui.tabix.io/ 2 DBeaverhttps://dbeaver.io/download/ 可视化工具操作 1 tabix tabix 支持通过浏览器直接连接 ClickHouse&#xff…