问题
i am a little new to asyncio in python. I was trying to run this simple code but i don't know why i am getting this unexpected output.
What i did is that, in outer
function, i created async tasks and stored it in an array tasks
. Before awaiting on these tasks i wrote a print statement print("outer")
that should run in every iteration. And inside the task i wrote another print statement print("inner")
in inner
function. But some how i am getting some unexpected output.
Here's the code -
import asyncio
def main():
loop = asyncio.get_event_loop()
loop.run_until_complete(outer(loop))
loop.close()
async def outer(loop):
tasks = []
for i in range(0, 5):
tasks.append(loop.create_task(inner()))
for task in tasks:
print("outer")
await task
async def inner():
print("inner")
await asyncio.sleep(0.5)
if __name__ == '__main__':
main()
Here's the output -
outer
inner
inner
inner
inner
inner
outer
outer
outer
outer
My Expected output was -
outer
inner
outer
inner
outer
inner
outer
inner
outer
inner
Why all the inner
are printing before outer
. What is the correct execution flow of asyncio. Thanks in advance.
回答1:
In async def outer(loop)
for i in range(0, 5):
tasks.append(loop.create_task(inner()))
- Five new
inner
tasks are created, scheduled and start running. - the event loop runs the scheduled tasks till they are completed.
If you add a little bit more to to inner
and outer
it shows this process better:
async def outer(loop):
tasks = []
for i in range(0, 5):
tasks.append(loop.create_task(inner(i)))
await asyncio.sleep(3)
for task in tasks:
print('outer')
await task
async def inner(n):
print(f"inner {n} start")
await asyncio.sleep(0.5)
print(f'inner {n} end')
while
outer
is sleeping- The first task runs to its await statement
- The event loop suspends execution of the first task
- The event loop runs the next schduled task up to its await statement
- This continues till each task has had a chance to run up to its await statement then the event loop starts looking around to see if any of the tasks are done waiting for whatever they were waiting for - if done it lets them run some more.
- This continues till all the tasks are done
You can see that the five tasks execute and finish before the second for loop even starts.
- in the second for loop each task has already completed so
await task
has nothing to wait for andouter
is printed five times in succession.
I'm a little hazy on the event loop controlling everything - I haven't found any explicit documentation for that - probably alluded to in the create_task
docs: Wrap the coro coroutine into a Task and schedule its execution.
When you create the task it gets scheduled. I have seen videos on pyvideo.org that shows that process, unfortunately I couldn't quickly find the one I wanted to link to.
回答2:
The loop.create_task(inner())
immediately queues all 5 inner
tasks for running, not await task
. The await task
suspends outer
until the first task is completely done, i.e. at least 0.5 seconds. During this, all inner
tasks have been run once up await
, including their print
.
async def outer(loop):
tasks = []
for i in range(0, 5):
# queues task immediately
tasks.append(loop.create_task(inner()))
for task in tasks:
print("outer")
# suspends for at least 0.5 seconds
await task
async def inner():
# runs immediately
print("inner")
await asyncio.sleep(0.5)
来源:https://stackoverflow.com/questions/60919909/asyncio-execution-flow-issue