Home > Mobile >  Slow function in python not running asyncronously
Slow function in python not running asyncronously

Time:01-01

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

CodePudding user response:

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")

CodePudding user response:

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.

  • Related