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
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值