Run tasks immediately and then wait

Viewed 70

I'm new to Python and have code similar to the following:

import time
import asyncio

async def my_async_function(i):
    print("My function {}".format(i))

async def start():
    requests = []

    # Create multiple requests
    for i in range(5):
        print("Creating request #{}".format(i))
        requests.append(my_async_function(i))

    # Do some additional work here
    print("Begin sleep")
    time.sleep(10)
    print("End sleep")

    # Wait for all requests to finish
    return await asyncio.gather(*requests)

asyncio.run(start())

No matter how long the "additional work" takes, the requests seem to only run after "End sleep". I'm guessing asyncio.gather is what actually begins to execute them. How can I have the requests (aka my_async_function()) start immediately, do additional work, and then wait for all to complete at the end?

Edit: Per Krumelur's comments and my own findings, the following results in what I'm looking for:

import time
import asyncio
import random

async def my_async_function(i):
    print("Begin function {}".format(i))
    await asyncio.sleep(int(random.random() * 10))
    print("End function {}".format(i))

async def start():
    requests = []

    # Create multiple requests
    for i in range(10):
        print("Creating request #{}".format(i))
        requests.append(asyncio.create_task(my_async_function(i)))

    # Do some additional work here
    print("Begin sleep")
    await asyncio.sleep(5)
    print("End sleep")

    # Wait for all requests to finish
    return await asyncio.gather(*requests)

asyncio.run(start())

This only works if my_async_function and the "additional work" both are awaitable so that the event loop can give each of them execution time. You need create_task (if you know it's a coroutine) or ensure_future (if it could be a coroutine or future) to allow the requests to run immediately, otherwise they still end up running only when you gather.

1 Answers

time.sleep() is a synchronous operation

You’ll want to use the asynchronous sleep and await it, E.g.

await asyncio.sleep(10)

Other async code will only run when the current task yields (I.e. typically when “await”ing something).

Using async code means you have to keep using async everywhere. Async operations are meant for I/O-bound applications. If “additional work” is mainly CPU-bound, you are better off using threads (but beware the global interpreter lock!)

Related