有没有办法保证asyncio.Task会立即启动?

时间:2015-11-30 10:03:24

标签: python python-3.x python-asyncio

import asyncio


l = asyncio.Lock()

async def test():
    print('locked' if l.locked() else 'unlocked')

    await l.acquire()
    # await asyncio.ensure_future(l.acquire())

    await asyncio.sleep(1)
    l.release()

async def main():
    await asyncio.gather(test(), test())

if __name__ == "__main__":
    loop = asyncio.get_event_loop()
    loop.run_until_complete(main())

我们启动两个test()协同程序,其中第一个立即锁定l.acquire()锁定,第二个打印locked状态。输出:

unlocked
locked

如果您要评论await l.acquire()行并取消注释下一行,则所有内容都会发生变化。输出将是:

unlocked
unlocked

这是因为在l.acquire()启动第二个test()后,任务中包含l.acquire()

有没有办法让test()任务在第二Function math(n As Integer) As Double Math = ((n - 1) * 2 + 5) * Abs((n - 1) - (n = 1)) End Function 之前尽快启动(并获得与原始代码相同的输出)?

1 个答案:

答案 0 :(得分:0)

看起来我找到了解决方案。我们需要全局锁定,以便在第一个任务开始时暂停第二个任务锁定检查:

import asyncio


l = asyncio.Lock()
check_lock = asyncio.Lock()

async def test():
    async with check_lock:
        print('locked' if l.locked() else 'unlocked')
        await asyncio.ensure_future(l.acquire())
        print('now', 'locked' if l.locked() else 'unlocked')

    await asyncio.sleep(1)
    l.release()

async def main():
    await asyncio.gather(test(), test())

if __name__ == "__main__":
    loop = asyncio.get_event_loop()
    loop.run_until_complete(main())

输出:

unlocked
now locked
locked
# 1 second delay here
now locked

但是在这里我们得到了另一个问题:第一个任务完全完成后,第二个任务将被暂停,这就是为什么我们在第二个锁定之前得到1秒的延迟。在原始示例中很难看到(因为test()等待单锁),这就是我添加第二次打印的原因。但是multiple locking of different resources立即启动协程可能很重要:我们应该仅锁定创建任务,但不是等待它。创建任务本身不会立即启动该任务(和l.acquire()),我们应该将控制权返回给事件循环。它可以由await asyncio.sleep(0)完成。这是原始代码的最终解决方案:

import asyncio


l = asyncio.Lock()
check_lock = asyncio.Lock()

async def test():
    async with check_lock:
        print('locked' if l.locked() else 'unlocked')
        task = asyncio.ensure_future(l.acquire())  # only create task
        await asyncio.sleep(0)  # return control to event loop, it allows lock to be locked before task completed
        print('now', 'locked' if l.locked() else 'unlocked')  # would be printed immediately

    await task  # and now we can await for task done
    await asyncio.sleep(1)
    l.release()

async def main():
    await asyncio.gather(test(), test())

if __name__ == "__main__":
    loop = asyncio.get_event_loop()
    loop.run_until_complete(main())

输出:

unlocked
now locked
locked
# no delay here
now locked