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()

posted on 2019-04-17 14:49  疯狂的小萝卜头  阅读(465)  评论(0编辑  收藏  举报