Python 中 Condition 的实现原理(一个锁连续 acquire 两次的应用场景)

Python 中 Condition 的实现原理
  • Condition 提供了实现一个生产者一个消费者情况下,非常方便的同步工具。Condition 怎么使用呢,一言不合上代码:
from threading import Thread,Condition,Lock
from time import sleep
from random import randint

def supplier(res_con, res_desk):
    print("Supplier Started", flush=True)
    # notify 前锁必须 acquire(),notify() 后必须 release() 才能让其他 wait() 返回
    res_con.acquire()
    while True:
        res = randint(1, 100)
        res_desk.append(res)
        print("Supplier Data Ready: " + str(res), flush=True)
        res_con.notify() 
        res_con.wait()
        
def nicotian(res_con, res_desk):
    print("Nicotian Started", flush=True)
    res_con.acquire()
    while True:
        # 进入时释放锁,然后阻塞,被唤醒后获取锁,然后返回
        res_con.wait() 
        res = res_desk.pop()
        sleep(1)
        print("Nicotian Dealed Data: " + str(res), flush=True)
        res_con.notify()
        
def main():
    # 材料状态控制
    res_con = Condition(Lock())
    # 材料桌
    res_desk = []
    # 吸烟者,消费者线程应该先准备好等待
    thread_nic = Thread(target=nicotian, args=(res_con, res_desk), daemon=True)
    thread_nic.start()
    sleep(1)
    # 供应者
    thread_supp = Thread(target=supplier, args=(res_con, res_desk), daemon=True)
    thread_supp.start()
    input("\n\n===Enter Any Key To Exit===\n\n")
    
if __name__ == '__main__':
    main()
  • 非常好奇wait()的逻辑进入时释放锁,然后阻塞,被唤醒后获取锁,然后返回是怎么实现的,明明只绑定了一个锁,阻塞如何实现的,被唤醒怎么实现的?
  • 原理:原来是维护了一个_waiters(这个不是服务员哦) 列表,在wait()中连续wait.acquire()两次,把自己阻塞;在调用notify()后,选择其中一个waiter.release()唤醒一个等待的线程。
  • 真真是:一个锁连续 acquire 两次的应用场景(刚学 Python 语法的时候不是说这样会死锁吗,原来只是学的不够深入而已)
  • 源码附上
def notify(self, n=1):
    if not self._is_owned():
        raise RuntimeError("cannot notify on un-acquired lock")
    all_waiters = self._waiters
    waiters_to_notify = _deque(_islice(all_waiters, n))
    if not waiters_to_notify:
        return
    for waiter in waiters_to_notify:
        waiter.release()
        try:
            all_waiters.remove(waiter)
        except ValueError:
            pass

def wait(self, timeout=None):
    if not self._is_owned():
        raise RuntimeError("cannot wait on un-acquired lock")
    waiter = _allocate_lock()  # 就是 Lock 本身
    waiter.acquire()
    self._waiters.append(waiter)
    saved_state = self._release_save()
    gotit = False
    try:    # restore state no matter what (e.g., KeyboardInterrupt)
        if timeout is None:
            waiter.acquire()
            gotit = True
        else:
            if timeout > 0:
                gotit = waiter.acquire(True, timeout)
            else:
                gotit = waiter.acquire(False)
        return gotit
    finally:
        self._acquire_restore(saved_state)
        if not gotit:
            try:
                self._waiters.remove(waiter)
            except ValueError:
                pass
  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Python机制是通过线程同步来实现的。在Python,线程同步的方式有两种:互斥(Lock)和信号量(Semaphore)。 互斥是一种最简单的机制,它用于控制对共享资源的访问。当一个线程获取到互斥时,其他线程就无法再访问该资源,只有等待该线程释放后才能访问。Python提供了threading模块来实现互斥,通过Lock类来创建对象并进行加和解操作,具体实现如下: ```python import threading lock = threading.Lock() def func(): lock.acquire() # 这里是需要加的代码块 lock.release() ``` 在上面的代码,我们创建了一个Lock对象,并通过acquire()方法获取,执行需要加的代码块后再通过release()方法释放。 信号量是一种允许多个线程同时访问共享资源的机制,它通过一个计数器来控制同时访问共享资源的线程数量。当计数器为1时,信号量就变成了互斥,只有一个线程能够访问共享资源。Python提供了Semaphore类来实现信号量,具体实现如下: ```python import threading sem = threading.Semaphore(3) # 最多允许3个线程同时访问共享资源 def func(): sem.acquire() # 这里是需要访问共享资源的代码块 sem.release() ``` 在上面的代码,我们创建了一个Semaphore对象,并通过acquire()方法获取信号量,执行需要访问共享资源的代码块后再通过release()方法释放信号量。 总的来说,Python机制实现原理就是通过互斥和信号量来实现线程同步,保证共享资源的安全访问。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值