一、线程条件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)的更多相关文章

  1. Python 之并发编程之进程下(事件(Event())、队列(Queue)、生产者与消费者模型、JoinableQueue)

    八:事件(Event()) # 阻塞事件:    e = Event() 生成事件对象e    e.wait() 动态给程序加阻塞,程序当中是否加阻塞完全取决于该对象中的is_set() [默认返回值 ...

  2. python线程事件Event(30)

    在python项目开发中,线程thread使用是比较常见的,在前面的文章中我们介绍了 python线程的创建 以及 线程互斥锁 ,今天还要额外介绍一个与线程相关的内容 – 事件Event. 一.pyt ...

  3. {Python之线程} 一 背景知识 二 线程与进程的关系 三 线程的特点 四 线程的实际应用场景 五 内存中的线程 六 用户级线程和内核级线程(了解) 七 python与线程 八 Threading模块 九 锁 十 信号量 十一 事件Event 十二 条件Condition(了解) 十三 定时器

    Python之线程 线程 本节目录 一 背景知识 二 线程与进程的关系 三 线程的特点 四 线程的实际应用场景 五 内存中的线程 六 用户级线程和内核级线程(了解) 七 python与线程 八 Thr ...

  4. Python之路(第四十五篇)线程Event事件、 条件Condition、定时器Timer、线程queue

    一.事件Event Event(事件):事件处理的机制:全局定义了一个内置标志Flag,如果Flag值为 False,那么当程序执行 event.wait方法时就会阻塞,如果Flag值为True,那么 ...

  5. Java多线程(五) —— 线程并发库之锁机制

    参考文献: http://www.blogjava.net/xylz/archive/2010/07/08/325587.html 一.Lock与ReentrantLock 前面的章节主要谈谈原子操作 ...

  6. python线程条件变量Condition(31)

    对于线程与线程之间的交互我们在前面的文章已经介绍了 python 互斥锁Lock / python事件Event , 今天继续介绍一种线程交互方式 – 线程条件变量Condition. 一.线程条件变 ...

  7. 15.python并发编程(线程--进程--协程)

    一.进程:1.定义:进程最小的资源单位,本质就是一个程序在一个数据集上的一次动态执行(运行)的过程2.组成:进程一般由程序,数据集,进程控制三部分组成:(1)程序:用来描述进程要完成哪些功能以及如何完 ...

  8. java 并发(五)---AbstractQueuedSynchronizer

    文章部分图片和代码来自参考文章. LockSupport 和 CLH 和 ConditionObject 阅读源码首先看一下注解 ,知道了大概的意思后,再进行分析.注释一开始就进行了概括.AQS的实现 ...

  9. Python并发编程-线程同步(线程安全)

    Python并发编程-线程同步(线程安全) 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 线程同步,线程间协调,通过某种技术,让一个线程访问某些数据时,其它线程不能访问这些数据,直 ...

  10. 面试题_1_to_16_多线程、并发及线程的基础问题

    多线程.并发及线程的基础问题 1)Java 中能创建 volatile 数组吗?能,Java 中可以创建 volatile 类型数组,不过只是一个指向数组的引用,而不是整个数组.我的意思是,如果改变引 ...

随机推荐

  1. 【Shell】DBeaver Enterprise Edition 5.1.1 Download

    DBeaver Enterprise Edition 5.1.1 Download mkdir -p /opt/downloads/dbeaver/dbeaver-ee-5.1.1 mkdir -p ...

  2. Experience Cloud

    通过Apex的方式上传 Topic: String communityId = [Select Id from Network where Name = 'MobileMNOCS'].Id; Inte ...

  3. ESLint未定义报错

    vue框架, ---   .eslintrc.js : module.exports = { root: true, env: { node: true }, 'extends': [ 'plugin ...

  4. 前端实现电子签名(web、移动端)通用组件

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  5. 关于XAF中ListView慢的总结与改善

    关于XAF中ListView慢的总结与改善: 一.数据访问模式改善:ListView中DataAccessMode中的改变:默认模式是Client,这在大多数情况下,适当的使用Server,Serve ...

  6. Flutter tab切换保持页面状态的两种方法

    当通过底部tabBar将页面在"首页"和"分类"之间进行切换的时候,每一次进入页面的时候该页面的数据都会重新加载.那么如何让页面保持原来的状态,而不是每次都要重 ...

  7. hdu 4283You Are the One

    The TV shows such as You Are the One has been very popular. In order to meet the need of boys who ar ...

  8. Xcode 12.x下载了iOS10.x模拟器无法创建对应Device问题修复

    转自: https://hiraku.tw/2021/04/6428/ 感谢原作者,如有侵权请评论联系删除文章 在升級到 Xcode 12 之後,有些人發現雖然 Xcode 允許安裝低版本的模擬器,但 ...

  9. 配dns

    cat /etc/resolv.conf

  10. 解决Delphi报Range check error错误

    没有深入研究,大体是Debug下编译的运行就报错,Release下编译的正常. 后来发现Debug模式下会打开越界检查. Project--> Option -->Delphi Compl ...