zoukankan      html  css  js  c++  java
  • 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),'	请消费食物')
                    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)+'	食物已消费完,请添加食物')
                    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+'	取钱成功!吐出钞票:'+str(draw_amount))
                        self.balance -= draw_amount
                        print(threading.current_thread().name+'操作之后	余额为:'+str(self.balance))
                    else:
                        print(threading.current_thread().name+'	取钱失败!余额不足!	当前余额为:'+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+'	存钱成功!存入钞票:'+str(deposit_amount))
                    self.balance += deposit_amount
                    print(threading.current_thread().name+'操作之后	余额为:'+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),'	请先消费食物')
                    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)+'	食物已消费完,请添加食物')
                    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+'	取钱成功!吐出钞票:'+str(draw_amount))
                        self.balance -= draw_amount
                        print(threading.current_thread().name+'操作之后	余额为:'+str(self.balance))
                    else:
                        print(threading.current_thread().name+'	取钱失败!余额不足!	当前余额为:'+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+'	存钱成功!存入钞票:'+str(deposit_amount))
                    self.balance += deposit_amount
                    print(threading.current_thread().name+'操作之后	余额为:'+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()
  • 相关阅读:
    EF架构~简洁关联表插入,优越的代码性能!
    基础才是重中之重~你是否真正了解TransactionScope?
    基础才是重中之重~如何整理BLL与DAL层的文件
    java Byte 和byte 差别及byte[ ]和string转换
    转: java的InputStream和OutputStream的理解
    java.awt.list java.util.list 区别
    java.util.Scanner 总结
    java .io OutputStream 与InputStream
    java 3中方法复制一个文件
    网络爬虫 简介
  • 原文地址:https://www.cnblogs.com/gudanaimei/p/14408838.html
Copyright © 2011-2022 走看看