Python3之并发(五)---线程条件(Condition)和事件(Event)
一、线程条件Condition(条件变量)
依赖锁对象(Lock,RLock),锁对象可以通过参数传入获得,或者使用自动创建的默认锁对象
当多个条件变量需要共享同一个锁时,建议传入锁对象
除了带有获取到锁的锁定池,Condition还包含一个未获取到锁的等待池,等待池中的线程处于等待阻塞状态,直到锁定池中的线程调用notify()/notifyAll()通知,得到通知后线程进入锁定池等待锁定
threading.Condition(lock=None)
条件变量对象,允许一个或多个线程等待,直到被另一个线程通知为止
lock: 使用的锁对象,默认None,使用RLock锁对象,其他值使用RLock或Lock锁对象
Condition对象的方法
Condition.acquire(*args)
加锁
获取锁,获取成功返回 True,否则返回 False Condition.release()
释放锁,没有返回值 Condition.wait(timeout=None)
等待通知的最大超时时间,线程进入等待池并释放锁,直到锁定池中的其他线程调用notify()/notifyAll()通知唤醒该线程
timeout时间内获取到通知返回 True,否则返回 False
timeut: 超时时间,浮点数,默认None
当没有获去到锁的线程调用该方法引发 RuntimeError 异常 Condition.notify(n=1)
唤醒等待池中的线程(默认n=1),收到通知的线程将自动调用acquire()方法尝试加锁,若等待池中有多个线程,则随机选择当中任意一个线程 Condition.notify_all()
唤醒等待池中的所有线程
示例
食物添加和消费
import threading class Food():
def __init__(self, Max):
#初始食物个数和要加入食物的最大个数
self.num = 0
self.max = Max '''
是否加入食物的标志
self._flag=True,表示需要加入食物,消费食物方法被堵塞
self._flag=False,表示消费食物,加入食物方法被堵塞
'''
self._flag = True
self.cond = threading.Condition() #加入食物方法
def food_producer(self):
with self.cond:
if self._flag:
for i in range(self.max):
self.num += 1
print(threading.current_thread().name+'线程已添加食物个数:',str(self.num),', 总共',str(self.num),'个')
print('当前食物个数:'+str(self.max),'\t请消费食物')
self._flag = False
self.cond.notify_all()
else:
self.cond.wait() #消费食物方法
def food_consumer(self):
with self.cond:
if self._flag:
self.cond.wait()
else:
for i in range(self.max):
self.num -= 1
print(threading.current_thread().name+'线程已消费食物个数:',str(i+1),',当前还剩食物个数:',str(self.num))
print('当前食物个数:'+str(self.num)+'\t食物已消费完,请添加食物')
self._flag = True
self.cond.notify_all() foo = Food(20)
threading.Thread(target=foo.food_producer, name='food_producer_thread').start()
threading.Thread(target=foo.food_consumer, name='food_consumer_thread').start()
存取钱
import threading #账户类
class Account:
def __init__(self, account_no, balance):
#账户编号和账户余额
self.account_no = account_no
self.balance = balance '''
存取钱标志
self._flag=True表示取钱,存钱方法被堵塞
self._flag=False表示存钱,取钱方法被堵塞
'''
self._flag = False
self.cond = threading.Condition() def getBlance(self):
return self.balance #提取现金方法
def draw(self, draw_amount):
with self.cond:
if not self._flag:
self.cond.wait()
else:
if self.balance >= draw_amount :
print(threading.current_thread().name+'\t取钱成功!吐出钞票:'+str(draw_amount))
self.balance -= draw_amount
print(threading.current_thread().name+'操作之后\t余额为:'+str(self.balance))
else:
print(threading.current_thread().name+'\t取钱失败!余额不足!\t当前余额为:'+str(self.balance))
self._flag = False
self.cond.notify_all() #存钱方法
def deposit(self,deposit_amount):
with self.cond:
if self._flag:
self.cond.wait()
else:
print(threading.current_thread().name+'\t存钱成功!存入钞票:'+str(deposit_amount))
self.balance += deposit_amount
print(threading.current_thread().name+'操作之后\t余额为:'+str(self.balance))
self._flag = True
self.cond.notify_all() acct = Account('987456',0) for i in range(5):
thread1 = threading.Thread(name="acct_deposit_thread", target=acct.deposit, args=(800,))
thread1.start()
thread2 = threading.Thread(name="acct_draw_thread", target=acct.draw, args=(900,))
thread2.start()
二、线程事件Event
Event是最简单的线程通信机制之一: 一个线程发出事件信号,其他线程等待接收该信号
不支持with 上下文
threading.Event
相当于Condition+用户自定义的Flag
Event管理一个内部标识(Flag),默认值是 False,调用 set() 方法可将Flag设置为 True ,也可以调用 clear() 方法可将Flag设置为False
当Flag=False时,调用 wait() 方法将进入阻塞状态,直到Flag为 true
Event对象的方法
Event.is_set()
Event内部标识为True返回 True Event.set()
将Event内部标识设为 True ,所有正在等待这个事件的线程将被唤醒
当标识为 True 时,调用 wait() 方法的线程不会被被阻塞 Event.clear()
将Event内部标识设为 False ,之后调用 wait() 方法的线程将会被阻塞,直到调用 set() 方法将内部标识再次设置为 True Event.wait(timeout=None)
线程阻塞的最大超时时间,此时间内线程一直被堵塞,直到内部标致为 True
timeout: 超时时间,默认None,浮点数,单位秒
调用该方法之前先释放锁,即调用release()释放锁,否则容易产生死锁
示例
食物添加和消费
import threading class Food():
def __init__(self, Max):
#初始食物个数和要加入食物的最大个数
self.num = 0
self.max = Max self.lock = threading.RLock()
self.event = threading.Event() #加入食物方法
def food_producer(self):
self.lock.acquire()
try:
if not self.event.is_set():
for i in range(self.max):
self.num += 1
print(threading.current_thread().name+'已添加食物个数:',str(self.num)+',当前总共',str(self.num),'个')
print('当前食物个数:'+str(self.max),'\t请先消费食物')
self.event.set()
self.lock.release()
else:
self.lock.release()
self.event.wait()
finally:
pass #消费食物方法
def food_consumer(self):
self.lock.acquire()
try:
if self.event.is_set():
for i in range(self.max):
self.num -= 1
print(threading.current_thread().name+'已消费食物个数:',str(i+1),'个食物,当前还剩余食物个数:',str(self.num))
print('当前食物个数:'+str(self.num)+'\t食物已消费完,请添加食物')
self.event.clear()
self.lock.release()
else:
print(threading.current_thread().name+'的内置标识为{}'.format(self.event.is_set()))
self.lock.release()
self.event.wait()
finally:
pass foo = Food(20) for i in range(2):
thread2 = threading.Thread(target=foo.food_consumer, name='消费者')
thread2.start()
thread1 = threading.Thread(target=foo.food_producer, name='生产者')
thread1.start()
存取钱
import threading #账户类
class Account:
def __init__(self,account_no,balance):
#账户编号和账户余额
self.account_no = account_no
self.balance = balance self.lock = threading.RLock()
self.event = threading.Event() def getBlance(self):
return self.balance #提取现金方法
def draw(self,draw_amount):
self.lock.acquire()
try:
if not self.event.is_set():
print(threading.current_thread().name+'的内置标识为{}'.format(self.event.is_set()))
self.lock.release()
self.event.wait()
else:
if self.balance >= draw_amount:
print(threading.current_thread().name+'\t取钱成功!吐出钞票:'+str(draw_amount))
self.balance -= draw_amount
print(threading.current_thread().name+'操作之后\t余额为:'+str(self.balance))
else:
print(threading.current_thread().name+'\t取钱失败!余额不足!\t当前余额为:'+str(self.balance))
self.event.clear()
self.lock.release()
finally:
pass def deposit(self,deposit_amount):
self.lock.acquire()
try:
if self.event.is_set():
self.lock.release()
self.event.wait()
else:
print(threading.current_thread().name+'\t存钱成功!存入钞票:'+str(deposit_amount))
self.balance += deposit_amount
print(threading.current_thread().name+'操作之后\t余额为:'+str(self.balance))
self.event.set()
self.lock.release()
finally:
pass acct = Account('987456', 0) #循环取存操作5次,
for i in range(5):
thread2 = threading.Thread(name="取钱者", target=acct.draw, args=(700,))
thread2.start()
thread1 = threading.Thread(name="存钱者", target=acct.deposit, args=(800,))
thread1.start()
Python3之并发(五)---线程条件(Condition)和事件(Event)的更多相关文章
- Python 之并发编程之进程下(事件(Event())、队列(Queue)、生产者与消费者模型、JoinableQueue)
八:事件(Event()) # 阻塞事件: e = Event() 生成事件对象e e.wait() 动态给程序加阻塞,程序当中是否加阻塞完全取决于该对象中的is_set() [默认返回值 ...
- python线程事件Event(30)
在python项目开发中,线程thread使用是比较常见的,在前面的文章中我们介绍了 python线程的创建 以及 线程互斥锁 ,今天还要额外介绍一个与线程相关的内容 – 事件Event. 一.pyt ...
- {Python之线程} 一 背景知识 二 线程与进程的关系 三 线程的特点 四 线程的实际应用场景 五 内存中的线程 六 用户级线程和内核级线程(了解) 七 python与线程 八 Threading模块 九 锁 十 信号量 十一 事件Event 十二 条件Condition(了解) 十三 定时器
Python之线程 线程 本节目录 一 背景知识 二 线程与进程的关系 三 线程的特点 四 线程的实际应用场景 五 内存中的线程 六 用户级线程和内核级线程(了解) 七 python与线程 八 Thr ...
- Python之路(第四十五篇)线程Event事件、 条件Condition、定时器Timer、线程queue
一.事件Event Event(事件):事件处理的机制:全局定义了一个内置标志Flag,如果Flag值为 False,那么当程序执行 event.wait方法时就会阻塞,如果Flag值为True,那么 ...
- Java多线程(五) —— 线程并发库之锁机制
参考文献: http://www.blogjava.net/xylz/archive/2010/07/08/325587.html 一.Lock与ReentrantLock 前面的章节主要谈谈原子操作 ...
- python线程条件变量Condition(31)
对于线程与线程之间的交互我们在前面的文章已经介绍了 python 互斥锁Lock / python事件Event , 今天继续介绍一种线程交互方式 – 线程条件变量Condition. 一.线程条件变 ...
- 15.python并发编程(线程--进程--协程)
一.进程:1.定义:进程最小的资源单位,本质就是一个程序在一个数据集上的一次动态执行(运行)的过程2.组成:进程一般由程序,数据集,进程控制三部分组成:(1)程序:用来描述进程要完成哪些功能以及如何完 ...
- java 并发(五)---AbstractQueuedSynchronizer
文章部分图片和代码来自参考文章. LockSupport 和 CLH 和 ConditionObject 阅读源码首先看一下注解 ,知道了大概的意思后,再进行分析.注释一开始就进行了概括.AQS的实现 ...
- Python并发编程-线程同步(线程安全)
Python并发编程-线程同步(线程安全) 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 线程同步,线程间协调,通过某种技术,让一个线程访问某些数据时,其它线程不能访问这些数据,直 ...
- 面试题_1_to_16_多线程、并发及线程的基础问题
多线程.并发及线程的基础问题 1)Java 中能创建 volatile 数组吗?能,Java 中可以创建 volatile 类型数组,不过只是一个指向数组的引用,而不是整个数组.我的意思是,如果改变引 ...
随机推荐
- PHP压缩二进制流转CSV文件
接口返回的数据是二进制流,需先BASE64解码,再进行解压缩,压缩的文件格式为ZIP,需使用Inflater进行解压,即可得到文件. java demo: 转成PHP代码: 贴上 原始二进制流数据,需 ...
- npm 局部安装 jbrowse
#此处不要加 -g参数 , -g 是全局安装 npm install @jbrowse/cli #用npx 才能使用这个包,无法按照官方文档直接使用 npx jbrowse --version
- vux方法
vuex 的备注 // vuex的公用数据放置处 state: { count: 0, }, // (方法) 在里面可以去修改state里面的数据(在这里面不能写异步操作) mutations: { ...
- 公司官网百度搜素优化(www.curetech.cc)
1. 解读" 百度搜素引擎网页质量白皮书 " . 链接:https://pan.baidu.com/s/1fD7Cm93qsK01M0K1M1cIKw 提取码:9krx 2. ...
- 2.5 OpenEuler 中C与汇编的混合编程
2.5 OpenEuler 中C与汇编的混合编程 任务详情 在X86_64架构下实践2.5中的内容,提交代码和实践截图 把2.5的内容在OpenEuler中重新实践一遍,提交相关代码和截图 任务一x8 ...
- 超棒的良心工具-OCR工具集
使用平台:Windows 虽然是OCR工具,但多了一个"集"字,原因在于该软件内置了搜狗网络OCR.本地离线OCR,不用key,还原天若OCR操作. 一句话:免去申请注册key登录 ...
- pyinstaller根据虚拟环境virtualenv进行打包,降低exe文件大小
问题:使用pyinstaller打包后,发现打的exe特别大,有近200M,又没有用几个库,代码也很少,怎么会打出这么大的包呢? 分析:在pyinstaller打包的过程中,可以看到窗口中出现了很多本 ...
- springcloud(七) - Sleuth链路追踪
服务跟踪的具体步骤 sleuth系统自动埋点并把数据发给zipkin,ziplin负责存储和展示数据. 具体实现 cmd执行jar 代码执行(server.licent都需要配) <!-- 添加 ...
- Oracle一次插入多条数据
Oracle一次插入多条数据(批量插入)语法:INSERT ALL INTO tableName (column1, column2, column_n) VALUES (expr1, expr2, ...
- 关于右值 std::move
今天发现一个情况,对容器map 进行 std::move 之后,原map被清空了. map<int, int> tmp; tmp[1] = 1; tmp[2] = ...