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:
- 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?
- 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.