zoukankan      html  css  js  c++  java
  • Python 中Semaphore 信号量对象、Event事件、Condition

    Semaphore 信号量对象

    信号量是一个更高级的锁机制。信号量内部有一个计数器而不像锁对象内部有锁标识,而且只有当占用信号量的线程数超过信号量时线程才阻塞。这允许了多个线程可以同时访问相同的代码区。

    Semaphore管理一个内置的计数器,每当调用acquire()时内置计数器-1;调用release() 时内置计数器+1;

    计数器不能小于0;当计数器为0时,acquire()将阻塞线程直到其他线程调用release()。

    直接上代码,我们把semaphore控制为3,也就是说,同时有3个线程可以用这个锁,剩下的线程也之只能是阻塞等待。

    # coding:utf-8
    
    import time
    import threading
     
    semaphore = threading.Semaphore(3)
    
     
    def func():
        if semaphore.acquire():
            print (threading.currentThread().getName() + '获取锁')
            time.sleep(5) 
            semaphore.release()
            print (threading.currentThread().getName() + '释放锁')
     
     
    for i in range(10):
        t1 = threading.Thread(target=func)
        t1.start()
    
    Thread-1获取锁
    Thread-2获取锁
    Thread-3获取锁
    Thread-3释放锁
    Thread-2释放锁
    Thread-4获取锁
    Thread-5获取锁
    Thread-1释放锁
    Thread-6获取锁
    Thread-6释放锁
    Thread-7获取锁
    Thread-4释放锁
    Thread-8获取锁
    Thread-5释放锁
    Thread-9获取锁
    Thread-8释放锁
    Thread-10获取锁
    Thread-7释放锁
    Thread-9释放锁
    Thread-10释放锁
    

    Event事件

    Event内部包含了一个标志位,初始的时候为false。
    可以使用使用set()来将其设置为true;
    或者使用clear()将其从新设置为false;
    可以使用is_set()来检查标志位的状态;
    另一个最重要的函数就是wait(timeout=None),用来阻塞当前线程,直到event的内部标志位被设置为true或者timeout超时。如果内部标志位为true则wait()函数理解返回。

    # coding:utf-8
    
    import threading
    import time
    event = threading.Event()
    
    
    def service():
        print('开启服务')
        event.wait()  # 括号里可以带数字执行,数字表示等待的秒数,不带数字表示一直阻塞状态
        print('服务开启成功')
    
    
    def start():
        time.sleep(3)
        print('开始执行业务')
        time.sleep(3)
        event.set()  # 默认为False,set一次表示True,所以子线程里的foo函数解除阻塞状态继续执行
    
    
    def conn():
        while True:
            if event.is_set() == False:
                print('数据库连接成功')
                time.sleep(1)
                event.set()
                event.wait()
                break
            
    
    t = threading.Thread(target=service, args=())  # 子线程执行foo函数
    t.start()
    t2 = threading.Thread(target=start, args=())  # 子线程执行start函数
    t2.start()
    t3 = threading.Thread(target=conn, args=())  # 子线程执行do函数
    t3.start()
    
    开启服务
    数据库连接成功
    服务开启成功
    开始执行业务
    

    Condition

    可以把Condition理解为一把高级的琐,它提供了比Lock, RLock更高级的功能,允许我们能够控制复杂的线程同步问题。threadiong.Condition在内部维护一个琐对象(默认是RLock),可以在创建Condigtion对象的时候把琐对象作为参数传入。Condition也提供了acquire, release方法,其含义与琐的acquire, release方法一致,其实它只是简单的调用内部琐对象的对应的方法而已。Condition还提供了如下方法(特别要注意:这些方法只有在占用琐(acquire)之后才能调用,否则将会报RuntimeError异常。):

    Condition.wait([timeout]):
    wait方法释放内部所占用的琐,同时线程被挂起,直至接收到通知被唤醒或超时(如果提供了timeout参数的话)。当线程被唤醒并重新占有琐的时候,程序才会继续执行下去。

    Condition.notify():
    唤醒一个挂起的线程(如果存在挂起的线程)。注意:notify()方法不会释放所占用的琐。

    Condition.notify_all()
    Condition.notifyAll()
    唤醒所有挂起的线程(如果存在挂起的线程)。注意:这些方法不会释放所占用的琐。
    以下为生产者消费者模式示例:

    # coding:utf-8
    
    from threading import Thread, Condition
    import time
    import random
     
    queue = []
    MAX_NUM = 10
    condition = Condition()
    
     
    class ProducerThread(Thread):
    
        def run(self):
            nums = range(5)
            global queue
            while True:
                condition.acquire()
                if len(queue) == MAX_NUM:
                    print ("Queue full, producer is waiting")
                    condition.wait()
                    print ("Space in queue, Consumer notified the producer")
                num = random.choice(nums)
                queue.append(num)
                print ("Produced", num)
                condition.notify()
                condition.release()
                time.sleep(random.random())
     
     
    class ConsumerThread(Thread):
    
        def run(self):
            global queue
            while True:
                condition.acquire()
                if not queue:
                    print ("Nothing in queue, consumer is waiting")
                    condition.wait()
                    print ("Producer added something to queue and notified the consumer")
                num = queue.pop(0)
                print ("Consumed", num)
                condition.notify()
                condition.release()
                time.sleep(random.random())
     
     
    ProducerThread().start()
    ConsumerThread().start()
    
  • 相关阅读:
    观察者与被观察者
    Gson和阿里的JSON简单对比
    银行卡输入特效 4个加一空格
    Android 点击空白处蕴藏键盘
    Android覆盖安装及常遇到的问题
    Android view中的requestLayout和invalidate方法
    医药行业GSP注册流程
    如何快速查询视图
    反写规则超额控制
    预算管理的操作步骤
  • 原文地址:https://www.cnblogs.com/gmhappy/p/11863961.html
Copyright © 2011-2022 走看看