Issue
Having read the documents and watched a number of videos, i am testing asyncio
as an alternative to threading
.
The docs are here: https://docs.python.org/3/library/asyncio.html
I have constructed the following code with the expectation that it would produce the following.
before the sleep
hello
world
But in fact is produces this (world
comes before hello
):
before the sleep
world
hello
Here is the code:
import asyncio
import time
def main():
''' main entry point for the program '''
# create the event loop and add to the loop
# or run directly.
asyncio.run(main_async())
return
async def main_async():
''' the main async function '''
await foo()
await bar()
return
async def foo():
print('before the sleep')
await asyncio.sleep(2)
# time.sleep(0)
print('world')
return
async def bar():
print('hello')
await asyncio.sleep(0)
return
if __name__=='__main__':
''' This is executed when run from the command line '''
main()
The main()
function calls the async main_async()
function which in turn calls both the foo
and bar
async functions and both of those run the await asyncio.sleep(x)
command.
So my question is: why is the hello
world
comming in the wrong (unexpected) order given that i was expecting world
to be printed approximately 2 seconds after hello
?
Solution
You await
ed foo()
immediately, so bar()
was never scheduled until foo()
had run to completion; the execution of main_async
will never do things after an await
until the await
has completed. If you want to schedule them both and let them interleave, replace:
await foo()
await bar()
with something like:
await asyncio.gather(foo(), bar())
which will convert both awaitables to tasks, scheduling both on the running asyncio event loop, then wait for both tasks to run to completion. With both scheduled at once, when one blocks on an await
(and only await
-based blocks, because only await
yields control back to the event loop), the other will be allowed to run (and control can only return to the other task when the now running task await
s or finishes).
Basically, you have to remember that asyncio
is cooperative multitasking. If you're only executing one task, and that task performs an await
, there is nothing else to schedule, so nothing else runs until that await
completes. If you block by any means other than an await
, you still hold the event loop, and nothing else will get a chance to run, even if it's ready to go. So to gain any benefit from asyncio
you need to be careful to:
- Ensure other tasks are launched in time to occupy the event loop while the original task(s) are blocking on
await
. - Ensure you only block via
await
, so you don't monopolize the event loop unnecessarily.
Answered By - ShadowRanger
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.