Python:Python编程:从入门到实践__超清版:线程

news2024/10/7 20:28:16

Python线程与安全

    • 实现线程安全有多重方式,常见的包括:锁,条件变量,原子操作,线程本地存储等。 💚
  • 1. 锁
  • 2. 条件变量
  • 3. 通过 join 阻塞当前线程
  • 4. 采用 sleep 来休眠一段时间
  • 5. 原子操作
  • 5.1 使用 threading.Lock( ) 替代 atomic 原子操作

线程安全是指:多线程并发访问共享资源时,不会导致数据的错误或不一致性,在多线程编程中,由于多个线程同时访问共享数据,那么这就可能导致数据竞争,死锁等问题。线程安全的实现是为了 避免这些问题的发生。

实现线程安全有多重方式,常见的包括:锁,条件变量,原子操作,线程本地存储等。
💚

1. 锁

锁是一种 常见的线程同步机制,用于控制对共享资源的访问,在 Python中,锁有两种类型:互斥锁和 读写锁。互斥锁在同一时刻只允许一个线程对共享数据进行操作,读写锁则允许 多个线程同时读取共享数据,但是只允许 一个线程进行写操作。

可以使用 threading.Lock() 或 threading.RLock() 来创建互斥锁或读写锁

下面这个例子:新建 5个线程,和一个全局变量,然后每个线程在 start() 后,会调用 线程的 run(self) 函数,该函数会将变量 自增10 , 通过 lock 锁,可以实现 变量读写安全。
class myThread(threading.Thread):
    def run(self):
        global x  # 声明一个共享数据 x
        lock.acquire() # 上锁
        x += 10  # 变量x 增加10
        print('%s: %d' %(self.name,x)) # self 是线程对象,可以通过selt.name 得到线程名
        lock.release() #解锁
       
# 设置全局变量 x 
x = 0
lock = threading.RLock() # 创建可置入锁
list_thread = []
for i in range(5):
    list_thread.append(myThread()) # 创建5个线程,放到同一列表中

for i in list_thread:
 	i.start()  # 开启线程

# 打印
Thread-1: 10
Thread-2: 20
Thread-3: 30
Thread-4: 40
Thread-5: 50

2. 条件变量

  条件变量时一种用于线程间通信的同步机制,用于在多个线程之间共享状态信息,以便线程可以等待某个条件的出现并被通知,通常情况下,一个线程会等待另一个线程 触发某个条件,当条件满足时,等待的线程被通知并继续执行。
  在Python 中,条件变量是通过 threading.Condition类实现的,Condition 类实际上是一个 锁对象,它允许多个线程等待某个条件的出现,当条件满足时,Condition 会自动通知等待的线程继续执行,可以使用 condition 对象的 wait( ) 方法使 线程等待某个条件的出现,使用 notify()  或者 notify_all( )  方法通知等待的线程。

💚 下面我通过一个生成者和消费者模型来说明

举例:如有几个生产车间,几个消费者,当生产到一定数量时,即可停止生产。

# 举例:有几个生产车间,几个消费者,当生产到一定数量时,即可停止生产
condition = threading.Condition() # 获取线程条件锁
sheep = ['1件产品','1件产品','1件产品','1件产品','1件产品','1件产品']
class Producer(threading.Thread):
    def __init__(self,name):
        super().__init__(name = name)
        pass
    def run(self):
        global condition,sheep
        while True:
            time.sleep(0.1)
            condition.acquire()  # 上锁
            if len(sheep) < 10:
                print(self.name + "生产了1件产品")
                sheep.append('1件产品')
                condition.notifyAll()
                pass
            else:
                print("仓库满了,请停止生产,并等待5s后生产")
                condition.wait()
                time.sleep(5)
                pass
            condition.release()
        pass
    pass
 
class Custome(threading.Thread):
    def __init__(self,name):
        super().__init__(name = name)
        pass
    def run(self):
        global condition,sheep
        while True:
            time.sleep(0.1)
            condition.acquire()
            if len(sheep) > 0:
                meat = sheep.pop()
                print(self.name + "购买了" + meat + ",还剩" + str(len(sheep)) + "件")
                condition.notifyAll
                pass
            else:
                print("对不起,买光了,请等待5s后再购买")
                condition.wait()
                time.sleep(5)
                pass
            condition.release()
        pass
    pass
    
p1 = Producer("1号生产车间")
p2 = Producer("2号生产车间")
p3 = Producer("3号生产车间")
p4 = Producer("4号生产车间")
p5 = Producer("5号生产车间")

p1.start()
p2.start()
p3.start()
p4.start()
p5.start()

c1 = Custome("小王")
c2 = Custome("小张")
c3 = Custome("小刘")
c4 = Custome("小李")

c1.start()
c2.start()
c3.start()
c4.start()    

在这里插入图片描述

3. 通过 join 阻塞当前线程

import threading
def thread_test(x,y):
    for i in range(x,y): # range函数 :生成一系列连续整数的函数
        print(i)

thread_01 = threading.Thread(name = 't1',target = thread_test,args=(1,50))
thread_02 = threading.Thread(name = 't2',target = thread_test,args=(11,20))

thread_01.start() # 启动线程1
thread_01.join() # 阻塞主线程,让线程thread_01 执行完毕后再执行后面的代码
print ("thread_01 run over")
print ("main thread ----!")
thread_02.start() # 启动线程2 
thread_02.join()
print ("thread_02run over")

// 打印结果
1
2
3
4
5
6
7
8
9
thread_01 run over
main thread ----!
11
12
13
14
15
16
17
18
19
thread_02run over

4. 采用 sleep 来休眠一段时间

# 方法2:通过 sleep来休眠当前线程

import time
import threading
def thread_sleep(x,y):
    print("子线程开始休眠 10s")
    time.sleep(10)  # 休眠10s
    print("子线程休眠结束")
    for i in range(x,y): # range函数 :生成一系列连续的函数
        print(i)
    print("子线程执行完毕")

thread_03 = threading.Thread(target = thread_sleep,daemon = False,args=(1,5)) #线程不会随着主线程退出而退出
thread_03.start()
print("主线线程执行完毕")  

# 打印结果
子线程开始休眠 10s
主线线程执行完毕
子线程休眠结束
1
2
3
4
子线程执行完毕

5. 原子操作

Python的 atmoic 模块提供了一种机制:来确保可与多线程并发使用的函数原子性,它实现了一个 锁机制,该锁机制可保证同一时刻只有一个线程能够访问指定的函数。

🧡🧡🧡 使用 atmoic 模块有以下步骤

  1. 导入atmoic 模块
    import atmoic
  2. 创建一个 atmoic.Atmoic 对象 用于同步访问
    lock = atmoic.Atmoic()
  3. 将需要的原子性操作代码包裹在 lock.atmoic( ) 中
    with lock.atmoic():

💚 举例 :我们可以使用 atmoic 模块确保两条线程能够同步递增一个计数器

# 在此示例中,我们在increment()函数内使用了lock.atomic()来确保任何时刻仅有一条线程能够访问计数器。
# 这样,即使多个线程同时执行increment()函数在计数器上进行递增,结果也将是唯一且正确的。在本例中,最终输出的计数器值将为2。

# 但是 atomic 这个库下载失败
# 1.通过清华教育镜像会下载失败
#2. 通过 https://pypi.org/project/atomic/ 页面中下载源代码 然后通过:pip install /path/to/atomic-x.x.x.tar.gz 也安装失败
# 3. PATHONPATH 已经安装
# 4. 怀疑是和C++环境冲突了
import atomic
count = 0
lock = atmoic.Atmoic()
def increment():
    global count
    with lock.atmoic():
        count += 1
        
# 创建三条线程并启动他们
thread_01 = threading.Thread(target = increment)
thread_02 = threading.Thread(target = increment)
thread_03 = threading.Thread(target = increment)

thread_01.start()
thread_02.start()
thread_03.start()

#等待三条线程执行完毕
thread_01.join()
thread_02.join()
thread_03.join()

# 输出3
print('count: ',count) 

5.1 使用 threading.Lock( ) 替代 atomic 原子操作

value = 0
lock = threading.Lock()

def atomic_add(num):
    global value
    with lock:
        value += num

# 示例运行代码
for i in range(10):
    t = threading.Thread(target=atomic_add, args=(1,))
    t.start()
    t.join()
print(value)  # 结果应为10

说明:
#在上述代码中,使用了 Python 中的线程锁来保证 value 变量的原子性。每个线程都会执行一次 atomic_add 函数,
# 其中使用了 with lock 语句来获取线程锁,确保在执行某个线程操作 value 时,没有其他线程在执行这个操作。
#如果你需要更高效的 atomic add 实现,可以考虑使用 ctypes 库,利用 C 语言函数来实现原子操作。

在这里插入图片描述

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

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

相关文章

HTTP请求中token、cookie、session有什么区别

cookie HTTP无状态的&#xff0c;每次请求都要携带cookie,以帮助识别身份服务端也可以向客户端set-cookie,cookie大小4kb默认有跨域限制&#xff1a;不可跨域共享&#xff0c;不可跨域传递cookie&#xff08;可通过设置withCredential跨域传递cookie&#xff09; cookie本地存…

【EXata】5.4 连接到互联网

目录 5.4 连接到互联网 5.4.1 Windows 互联网网关配置 5.4.3 验证互联网网关配置 5.4 连接到互联网 EXata 允许在操作主机上运行的基于 Internet 的应用程序通过模拟网络连接到 Internet。这使得即时通讯、流媒体视频、VoIP 等应用程序可以像在现实世界中一样在 EXata 上运行。…

理解Java关键字volatile

原文链接 理解Java关键字volatile 在Java中&#xff0c;关键字volatile是除同步锁以外&#xff0c;另一个同步机制&#xff0c;它使用起来比锁要简单方便&#xff0c;但是却很容易被忽略&#xff0c;或者被误用。这篇文章就来详细讲解一下volatile它的作用&#xff0c;它的原理…

【图像水印 2022 ACM】PIMoG

【图像水印 2022 ACM】PIMoG 论文题目&#xff1a;PIMoG: An Effective Screen-shooting Noise-Layer Simulation for Deep-Learning-Based Watermarking Network 中文题目&#xff1a;PIMoG:深度学习水印网络中一种有效的截屏噪声层仿真 论文链接&#xff1a;https://dl.acm.o…

Redis-- 缓存预热+缓存雪崩+缓存击穿+缓存穿透

Redis-- 缓存预热缓存雪崩缓存击穿缓存穿透**加粗样式** 一 面试题引入二 缓存预热三 缓存雪崩3.1 问题现象3.2 预防解决 四 缓存穿透4.1 定义4.2 解决方案4.2.1 空对象缓存或者缺省值4.2.2 Google布隆过滤器Guava解决缓存穿透 五 缓存击穿5.1 定义5.2 危害5.3 解决 六 总结 一…

Excel·VBA统计多部门多商品销售量前10%的商品

如图&#xff1a;根据表中唯一的货品ID&#xff0c;有m个事业部中分别有n种货品&#xff0c;统计各事业部销量前10%的货品名称&#xff0c;生成统计表&#xff08;以下为2种统计方式&#xff09; 目录 仅统计货品ID方法1&#xff1a;字典嵌套字典结果 方法2&#xff1a;自定义函…

【LED子系统】十、详细实现流程(番外篇)

个人主页&#xff1a;董哥聊技术 我是董哥&#xff0c;高级嵌入式软件开发工程师&#xff0c;从事嵌入式Linux驱动开发和系统开发&#xff0c;曾就职于世界500强公司&#xff01; 创作理念&#xff1a;专注分享高质量嵌入式文章&#xff0c;让大家读有所得&#xff01; 文章目录…

Hive ---- 文件格式和压缩

Hive ---- 文件格式和压缩 1. Hadoop压缩概述2. Hive文件格式1. Text File2. ORC3. Parquet3. 压缩1. Hive表数据进行压缩2. 计算过程中使用压缩 1. Hadoop压缩概述 为了支持多种压缩/解压缩算法&#xff0c;Hadoop引入了编码/解码器&#xff0c;如下表所示&#xff1a; Hadoo…

CodeForces..李华和迷宫.[简单].[找规律]

题目描述&#xff1a; 题目解读&#xff1a; 存在矩阵迷宫nm&#xff0c;&#xff08;r&#xff0c;c&#xff09;表示从顶部开始的第r行和左起第c列。 如果两单元格共享一个边&#xff0c;则是相邻的。路径是相邻空单元格的序列。 每个单元格初始状态都为空。对于从&#x…

代码随想录额外题目——图论部分

记录一下代码随想录中额外题目的图论部分 841.钥匙和房间 有 n 个房间&#xff0c;房间按从 0 到 n - 1 编号。最初&#xff0c;除 0 号房间外的其余所有房间都被锁住。你的目标是进入所有的房间。然而&#xff0c;你不能在没有获得钥匙的时候进入锁住的房间。 当你进入一个…

山海大模型亮相,云知声交出AGI第一份答卷

有人说&#xff0c;AI大模型是少数巨头才能玩得转的游戏。 截至目前&#xff0c;认同此观点的人不在少数。自从ChatGPT去年迅速火遍全球之后&#xff0c;忽如一夜春风来&#xff0c;AI大模型遍地开。Google、Amazon、阿里、百度等巨头们纷纷加入AI大模型的“军备竞赛”&#x…

【数据分享】1929-2022年全球站点的逐日平均气温数据(Shp\Excel\无需转发)

气象数据是在各项研究中都经常使用的数据&#xff0c;气象指标包括气温、风速、降水、湿度等指标&#xff0c;其中又以气温指标最为常用&#xff01;说到气温数据&#xff0c;最详细的气温数据是具体到气象监测站点的气温数据&#xff01;本次我们为大家带来的就是具体到气象监…

大数据分析案例-基于决策树算法构建世界杯比赛预测模型

&#x1f935;‍♂️ 个人主页&#xff1a;艾派森的个人主页 ✍&#x1f3fb;作者简介&#xff1a;Python学习者 &#x1f40b; 希望大家多多支持&#xff0c;我们一起进步&#xff01;&#x1f604; 如果文章对你有帮助的话&#xff0c; 欢迎评论 &#x1f4ac;点赞&#x1f4…

EMC VNX Unified Storage 关机顺序方法

EMC Unfied的VNX存储系统要比单纯的Block系统复杂很多&#xff0c;相当于是两套存储系统&#xff0c;不管在物理硬件上还是逻辑的软件OS上&#xff0c;都复杂很多很多。 客户经常遇到由于机房停电或者机房搬迁等情况&#xff0c;需要对存储系统做关机下电甚至物理搬迁的动作&a…

FPGA基于AXI 1G/2.5G Ethernet Subsystem实现UDP通信DMA传输 提供工程源码和技术支持

目录 1、前言2、我这里已有的UDP方案3、详细设计方案传统UDP网络通信方案本方案详细设计说明DMA和BRAMAXIS-FIFOUDP模块设计UDP模块FIFOAXI 1G/2.5G Ethernet Subsystem&#xff1a;输出 4、vivado工程详解5、上板调试验证并演示注意事项 6、福利&#xff1a;工程代码的获取 1、…

【simple-cache】一款只用一个注解就实现缓存的框架-我们终于迎来了SpringBoot版本

上次我们讲了【simple-cache】的使用&#xff1a; 【simple-cache】我开发了一款只要一个注解就可以轻松实现缓存的框架 这次主要更新的内容为&#xff1a; 添加springboot项目框架中去除了redisconfig类&#xff0c;避免了redis的单机和集群问题用户可以自定义使用自己项目中…

Python之字符串(str)基础知识点

strip() 删除指定字符 当token为空时,默认删除空白符(含’\n’,‘\r’,‘\t’,’ )&#xff0c;当非空时&#xff0c;根据指定的token进行删除。 字符的删除又可分为以下几种情况&#xff1a; string.strip(token)&#xff1a;删除string字符串中开头(left)、结尾处(right)的…

【操作系统】02.进程管理

多道程序系统 多道就是将多个程序同时装入内存&#xff0c;使之并发运行。操作系统也是基于多道产生的&#xff0c;提高了资源利用率和系统吞吐量。 进程 定义 进程是程序的一次执行 进程是进程实体的运行过程&#xff0c;是系统进行资源分配和调度的一个独立单位 在引入线…

会流程图却不会UML活动图?活动图深度剖析,就怕你学不会!

1. UML活动图是啥&#xff1f; 也许很多人都不怎么了解活动图&#xff0c;但是却对流程图很熟悉&#xff0c;你暂且可以简单的把活动图理解为UML里的流程图&#xff0c;用来描述系统的行为特征。不过UML活动图对比于流程图来说也存在不少差异&#xff0c;本文将在第三章节讲解活…

解决 MobaXterm X11 server 打开 wsl2 linux 子系统 rviz 可视化窗口卡顿问题

1、问题 环境&#xff1a; MobaXtermwsl2 Ubuntu-18.04ROS1Intel 核显 一直使用 MobaXterm 这个远程软件 ssh 链接 linux 服务器&#xff0c;因为它集成了 X11 server&#xff0c;即可以显示一些 linux 下有图形化界面的程序&#xff0c;如 ROS 的 rviz 等。 但是 MobaXterm…