Let’s say I have two functions which return similar results. I want to call both and take the results of whichever returns first. So lets say I have two async functions which wait 5 and 2 seconds like so:
import asyncio from time import sleep async def func_1(): for i in range(5): print("func 1") sleep(1) return "slept for 5" async def func_2(): for i in range(2): print("func 2") sleep(1) return "slept for 2"
And I have a function which calls them like so:
async def competition(): task2 = asyncio.create_task(func_1()) task1 = asyncio.create_task(func_2()) done, pending = await asyncio.wait([task1, task2], return_when=asyncio.FIRST_COMPLETED) print(len(pending)) print(len(done))
As you see the competition function uses asyncio.wait
to run the two tasks and returns the results based on the FIRST_COMPLETED
function. The documentation defines FIRST_COMPLETED
as:
The function will return when any future finishes or is cancelled.
Also, I run the competition
function as shown bellow.
asyncio.run(competition())
However, it does not return when one task is done. It returns when both are done. Furthermore, the asyncio.wait() method is defined as a concurrent executer.
Run awaitable objects in the aws iterable concurrently and block until the condition specified by return_when.
However, that is not what happens. The tasks run in a single thread and one runs after the other. So the result that I get if I run the code is this:
func 1 func 1 func 1 func 1 func 1 func 2 func 2 0 2
Am I missing anything? Or have I misunderstood how it works?
FYI: I am using python 3.10.
Advertisement
Answer
You’ve been using time.sleep
in your code. When you chage your time.sleep
calls in your code to await asyncio.sleep(1)
, the results are:
func 1 func 2 func 1 func 2 func 1 1 1
I had some hard time wrapping my head around how async programming works, but in my understanding asyncio
is by design supposed to run everything in a single thread (cooperative multithreading). It pauses the execution of a given function, when it encounters a call such as await asyncio.sleep(1)
and moves on to execute other functions that are scheduled for execution. The ordinary time.sleep
does not allow asyncio
to pause the execution.