Suppose, I have a few async functions, f1, f2 and f3. I want to execute these functions in a sequential order. The easiest way to do this would be to await on them:
async def foo():
await f1()
# Do something else
await f2()
# Do something else
await f3()
# Do something else
However, I don't care about the results of these async functions, and I would like to continue with the execution of the rest of the function after scheduling the async functions.
From the asyncio tasks documentation it seems that asyncio.ensure_future() can help me with this. I used the following code to test this out, and the synchronous parts of foo() as per my expectations. However, bar() never executes past asyncio.sleep()
import asyncio
async def bar(name):
print(f'Sleep {name}')
await asyncio.sleep(3)
print(f'Wakeup {name}')
async def foo():
print('Enter foo')
for i in [1, 2, 3]:
asyncio.ensure_future(bar(i))
print(f'Scheduled bar({i}) for execution')
print('Exit foo')
loop = asyncio.get_event_loop()
loop.run_until_complete(foo())
The output for the above code:
Enter foo
Scheduled bar(1) for execution
Scheduled bar(2) for execution
Scheduled bar(3) for execution
Exit foo
Sleep 1
Sleep 2
Sleep 3
So, what is the proper method to do what I'm looking for?
I have a few async functions,
f1,f2andf3. I want to execute these functions in a sequential order. [...] I would like to continue with the execution of the rest of the function after scheduling the async functions.
The straightforward way to do this is by using a helper function and letting it run it in the background:
async def foo():
async def run_fs():
await f1()
await f2()
await f3()
loop = asyncio.get_event_loop()
loop.create_task(run_fs())
# proceed with stuff that foo needs to do
...
create_task submits a coroutine to the event loop. You can also use ensure_future for that, but create_task is preferred when spawning a coroutine.
The code in the question has two issues: first, the functions are not run sequentially, but in parallel. This is fixed as shown above, by running a single async function in the background that awaits the three in order. The second problem is that in asyncio run_until_complete(foo()) only waits for foo() to finish, not also for the tasks spawned by foo (though there are asyncio alternatives that address this). If you want run_until_complete(foo()) to wait for run_fs to finish, foo has to await it itself.
Fortunately, that is trivial to implement - just add another await at the end of foo(), awaiting the task created for run_fs earlier. If the task is already done by that point, the await will exit immediately, otherwise it will wait.
async def foo():
async def run_fs():
await f1()
await f2()
await f3()
loop = asyncio.get_event_loop()
f_task = loop.create_task(run_fs())
# proceed with stuff that foo needs to do
...
# finally, ensure that the fs have finished by the time we return
await f_task
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With