异步循环和锁

Asyncio Loop and Lock

我正在研究 asyncio 循环和锁,发现了一些我认为很奇怪的东西

import asyncio
import time
lock = asyncio.Lock()

async def side_func():
    print("trying to acquire Side")
    await lock.acquire()
    print("Acquired side")
    lock.release()

async def func2():
    print("Trying to aacquire 2nd")
    await lock.acquire()
    print("Acquired second")
    lock.release()
    
async def func1():
    print("Acquiring 1st")
    await lock.acquire()
    await asyncio.sleep(2)
    print("Acquired 1st")
    lock.release()
    await side_func()


async def main():
    await asyncio.wait([func1(), func2()])
    
asyncio.run(main())

首先给出此代码 runes func1,它应该首先能够获取 func1 的锁,跳转到 asyncio.sleep(2) 上的 func2 并等待锁定在那里,当睡眠结束时它应该执行 side func.

但是当尝试为 side_func 获取锁时,事件循环反而跳转到 func2 并在那里获取锁。我的理解应该是先获取side_func中的锁,然后才能跳转到其他函数

出于某种原因,它首先跳转到废弃的 func2 函数,这是全局适用于异步函数的行为还是特定于 lock.acquire?我想事件循环首先跳转到已放弃但已完成的状态是有意义的,但我不确定这是否全局适用于异步函数

锁的内部行为是这段代码:

def release(self):
    """Release a lock.

    When the lock is locked, reset it to unlocked, and return.
    If any other coroutines are blocked waiting for the lock to become
    unlocked, allow exactly one of them to proceed.

    When invoked on an unlocked lock, a RuntimeError is raised.

    There is no return value.
    """
    if self._locked:
        self._locked = False
        self._wake_up_first()
    else:
        raise RuntimeError('Lock is not acquired.')

所以它所做的是每次你释放你的锁时,它都会尝试唤醒下一个服务员(最后一个调用这个锁的协程),它是:

fut = next(iter(self._waiters))

因为锁实现了一个存储等待者的队列

def __init__(self, *, loop=None):
    self._waiters = collections.deque()
    self._locked = False

下一个服务员是第一个叫锁的服务员。

执行代码时:

Acquiring 1st
Trying to aacquire 2nd
Acquired 1st
trying to acquire Side
Acquired second
Acquired side

我们清楚地看到第二个在前面等待。因此,当 1st 释放它时,将要唤醒的是 func2,而不是 Side。