1

I have a slow function in python that I want to run asynchronously. This slow function is basically a very long loop, like the following:



def slow(slowness):
    print(f"Slow loop {slowness}")
    for i in range(int(slowness * 1e8)):
        i
    print(f"Wait for loop {slowness} finished")


if __name__ == '__main__':

    slow(1)
    slow(0.5)
    slow(0.1)

I'm trying to run the asynchronous version, using the following code:

import asyncio

async def slow(slowness):
    print(f"Slow loop {slowness}")
    for i in range(int(slowness * 1e8)):
        i
    print(f"Wait for loop {slowness} finished")


async def main() -> None:
    await asyncio.gather(
        slow(1),
        slow(0.5),
        slow(0.1)
    )


if __name__ == '__main__':
    asyncio.run(main())

I would expect the function with slowness=0.1 to finish the execution first, but I am seeing a regular execution that seems synchronous. What am I doing wrong?

I'm seeing the following output:

Waiting for 1 seconds...
Wait for 1 seconds finished
Waiting for 0.5 seconds...
Wait for 0.5 seconds finished
Waiting for 0.1 seconds...
Wait for 0.1 seconds finished

and I'd expect something like:

Waiting for 1 seconds...
Waiting for 0.5 seconds...
Waiting for 0.1 seconds...
Wait for 0.1 seconds finished
Wait for 0.5 seconds finished
Wait for 1 seconds finished

2 Answers 2

2

Other tasks/coroutines will only be executed when the currently executing task/coroutine yields control back to the event loop by awaiting. slow does not await anything so never yields control back to the event loop therefore the other tasks don't execute until the current task completes.

await asyncio.sleep(0) will yield control but execute as soon as possible

async def slow(slowness):
    print(f"Slow loop {slowness}")
    for i in range(int(slowness * 1e8)):
        await asyncio.sleep(0)
    print(f"Wait for loop {slowness} finished")

Better would be to just sleep for the correct amount of time

async def slow(slowness):
    print(f"Slow loop {slowness}")
    await asyncio.sleep(slowness)
    print(f"Wait for loop {slowness} finished")
Sign up to request clarification or add additional context in comments.

Comments

1

Asyncio is not magic. It will not suddenly endow your processor with three times its current computing capability. I offer this simple checklist to determine whether asyncio can speed up your program:

  1. Does my program spend a significant amount of time waiting on resources, such as a network, a database, or (in my case) a set of instruments?
  2. While it is waiting, is there something useful it could be doing instead?

If the answer to both of these questions is yes, then consider using asyncio for a performance improvement. Otherwise not.

This is not the only use-case for asyncio, but it's the one you seem to be interested in. There's a reason why the Python folks put the asyncio documentation under "Networking and Interprocess Communication" rather than "Concurrent Execution."

To speed up a number-crunching type of program, you probably want to look at the multiprocessing package in the standard library, which supports true parallel computing.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.