For some reason, this code doesn't work on Ubuntu 20, Python 3.8.10, unless the .gather line is commented out.
It works on Ubuntu 24, Python 3.12.3 and Windows 11, Python 3.13.9.
It doesn't work on Python 3.8/3.9 on the same Ubuntu 24 machine. It seems to work from Python 3.10 onwards, so the issue appears to be one with the Python version.
This code is a minimum working example of the issue that I'm facing. Assume that the locks are actually necessary.
import asyncio
import time
lock = asyncio.Lock()
async def action():
print("action")
return
async def task1():
while True:
print("1 waiting")
await lock.acquire()
print("1 running")
await asyncio.gather(*[action() for _ in range(1)])
lock.release()
print("1 unlocked")
print("A", time.time())
await asyncio.sleep(1)
print("B", time.time())
async def task2():
while True:
print("2 waiting")
await lock.acquire()
print("2 running")
lock.release()
print("2 unlocked")
await asyncio.sleep(1)
async def main():
task1_ = asyncio.create_task(task1())
task2_ = asyncio.create_task(task2())
while True: await asyncio.sleep(float('inf'))
if __name__ == "__main__":
asyncio.run(main())
The output on one of the Python versions that works is:
$ python3 test.py
1 waiting
1 running
2 waiting
action
1 unlocked
A 1763606395.8323498
2 running
2 unlocked
B 1763606396.843853
1 waiting
1 running
2 waiting
action
1 unlocked
A 1763606396.8451693
2 running
2 unlocked
B 1763606397.8484037
Notice that task2 gets to run between A and B (while task1 is asleep).
The output of the non-working versions is:
$ python3 test.py
1 waiting
1 running
2 waiting
action
1 unlocked
A 1763606434.4998655
B 1763606435.5010738
1 waiting
1 running
action
1 unlocked
A 1763606435.5020432
B 1763606436.5031264
1 waiting
1 running
action
1 unlocked
A 1763606436.5039277
B 1763606437.5050313
As you can see, task2 doesn't run between A and B.
This issue occurs regardless of using await lock.acquire() or async with lock:.
If I comment out the .gather line, it works on all versions.
However, I need to run multiple tasks at the same time, so I can't simply comment that out.
I haven't been able to find anything in the docs that suggests an issue with gather or locks in older versions of asyncio.
So what's going on here, and how do I fix it?