-
-
Notifications
You must be signed in to change notification settings - Fork 31.8k
"Coroutines and Tasks" page does not appear to be clear about what asyncio.create_task
does
#96023
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
For further consideration: I am now seeing that an Async tutorial appears to be in the works since September 2018. This looks nice. The "Three Ways To Execute Async Functions" page in the future Asyncio tutorial seems to be a better place to clarify how the (
This paragraph explains |
This is an implementation detail, when task starts running depends upon the number of iterations of loop required before it hits You should use the new |
Using The key thing to know is that tasks and coroutines (async functions) only run when you The next thing to know is that I'm not sure that the docs make this clear enough, someone should have a look and then report back here or submit a PR. |
Thanks @gvanrossum , those insights I hadn't seen elsewhere yet, very helpful. It's an important distinction to make:
...whereas all other...
which is the usual case in C# async code. So Is the difference rooted in .NET being natively multi-threaded, so it can spin up those "background jobs" trivially? Python doesn't have that luxury (GIL). It (the event loop) has to patiently wait until control is yielded back to it cooperatively, as control (in the sense of "instruction pointer"/"program counter") can only ever be in one place at a time. C# async is also based around coroutines though, so that part seems surprisingly similar. Hope I'm not talking rubbish here. As for the linked guide, it seems outdated. It claims:
for the snippet: import asyncio
async def f():
await asyncio.sleep(10)
print('f is done')
async def g():
await asyncio.sleep(5)
print('g is done')
async def main():
asyncio.create_task(f()) # (1)
await g() # (2)
asyncio.run(main()) which, when run under Python 3.11.2, only prints But adjusting the snippet makes for a good showcase of what @gvanrossum had mentioned: import asyncio
async def f():
print('starting f')
await asyncio.sleep(10)
print('f is done')
async def g():
print('starting g')
await asyncio.sleep(5)
print('g is done')
async def main():
print('starting main')
asyncio.create_task(f())
print('scheduled f')
await g()
print('bye')
asyncio.run(main()) outputs:
which seems deterministic on my machine. So clearly, An open question would still be the behavior when commenting out
which is... interesting! So the event loop gets control just before interpreter shutdown, it seems (?). Would not have expected that. |
Um, sorry, I don't think the issue tracker is the right place to educate you. You are drawing parallels to C# tasks, which is probably just confusing. If you want to have a discussion, please start a thread on discuss.python.org. |
@alexpovel I wrote that now old documentation. You are correct that It was correct about f being started implicitly (that You can verify this by modifying the example slightly: import asyncio
async def f():
print('start running f')
try:
await asyncio.sleep(10)
except asyncio.CancelledError:
print('f was cancelled')
raise
print('f is done')
async def g():
await asyncio.sleep(5)
print('g is done')
async def main():
asyncio.create_task(f()) # (1)
print('about to start g')
await g() # (2)
asyncio.run(main()) This is the output:
You can see that |
@cjrh (or anyone still reading this): If the docs are actually incorrect, could you send a PR to fix it? (Or if it was already fixed, indicate here by which PR.) |
The error was in my asyncio-tutorial PR which never got merged and is now closed (so there are no docs in main branch to fix here). I don't know who if anyone is going to take that work further, but I'll have a look around. |
Sorry for the confusion. Good luck! And thanks for trying. |
In the documentation (specifically, in the "Coroutines and Tasks" page), I am having trouble understanding what happens when
asyncio.create_task
is called. I have read the headings Coroutines and Creating tasks, but I still don't get it.Replicating the issue
This can be done by reading the "Coroutines and Tasks" page while trying to learn the explanations and references to the
asyncio.create_task
."Coroutines" heading
In the third point under the "three main mechanisms", the following example is provided:
My question here is: when does the
say_after(2, 'world')
start running? I see three options:task2 = asyncio.create_task(say_after(2, 'world'))
await task1
await task2
In the third point under the "three main mechanisms", it is further explained (bold added here):
Why is the output "expected"? I am not finding any explanation of why this 1-sec-faster behavior is expected.
"Creating tasks" heading
In this heading, the first line of the
__doc__
string forasyncio.create_task
explains the following (bold added here):I don't understand what is the meaning of "schedule its execution". Does the
coro
get scheduled to run now or only when the program hits the nextawait
statement?Suggested solution
Either in the "Coroutines" heading or in the "Creating tasks" heading, inserting an explicit clarification of when the task starts running.
The text was updated successfully, but these errors were encountered: