Skip to content Skip to sidebar Skip to footer

Is There Any Way To Guarantee Asyncio.task Will Be Started Immediately?

import asyncio l = asyncio.Lock() async def test(): print('locked' if l.locked() else 'unlocked') await l.acquire() # await asyncio.ensure_future(l.acquire())

Solution 1:

Looks like I found solution. We need global lock that would suspend second task locked checking while first task starts:

import asyncio


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

asyncdeftest():
    asyncwith 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()

asyncdefmain():
    await asyncio.gather(test(), test())

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

Output:

unlocked
now locked
locked
# 1 second delay here
now locked

But here we get another problem: second task would be suspended while first task completely done, that's why we get 1 second delay before second locking. It was hard to see in original example (because test() wait for single lock), that's why I added second printing. But it can be important for multiple locking of different resources to start coroutine immediately: we should lock only creating task, but not it's awaiting. Creating task itself wouldn't start that task (and l.acquire()) immediately, we should return control to event loop. It can be done by await asyncio.sleep(0). Here's final solution for original code:

import asyncio


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

asyncdeftest():
    asyncwith check_lock:
        print('locked'if l.locked() else'unlocked')
        task = asyncio.ensure_future(l.acquire())  # only create taskawait asyncio.sleep(0)  # return control to event loop, it allows lock to be locked before task completedprint('now', 'locked'if l.locked() else'unlocked')  # would be printed immediatelyawait task  # and now we can await for task doneawait asyncio.sleep(1)
    l.release()

asyncdefmain():
    await asyncio.gather(test(), test())

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

Output:

unlocked
now locked
locked
# no delay here
now locked

Post a Comment for "Is There Any Way To Guarantee Asyncio.task Will Be Started Immediately?"