classification
Title: asyncio task chapter confusion about 'task', 'future', and 'schedule'
Type: behavior Stage:
Components: asyncio, Documentation Versions: Python 3.4, Python 3.5
process
Status: open Resolution:
Dependencies: Superseder:
Assigned To: docs@python Nosy List: docs@python, giampaolo.rodola, gvanrossum, pitrou, r.david.murray, vstinner, yselivanov
Priority: normal Keywords:

Created on 2014-09-24 01:34 by r.david.murray, last changed 2014-09-24 14:50 by vstinner.

Messages (2)
msg227405 - (view) Author: R. David Murray (r.david.murray) * (Python committer) Date: 2014-09-24 01:34
Sorry for creating all these doc issues, but I'm reading these docs for the first time, and I figure it is good to capture my confusion now in the hopes that they can be clarified for other people's first readthroughs.

In the task chapter, we have Futures introduced.  (As an aside, it is interesting that the link to the concurrent.futures.Future docs start by saying "you should never instantiate this class directly", but the asyncio examples show direct instantiation of a future, but this difference is not mentioned in the asyncio docs when discussing the differences between them).  We then see an example that appears to include scheduling a future via asyncio.async, because there is a specific mention of how we can attach a callback after it is scheduled but before the event loop is started.

Then tasks are introduced with the text:

  Schedule the execution of a coroutine: wrap it in a future.  A task is a subclass of Future.

Now, having read a bit more elsewhere in the docs, I see that a Future is scheduled by its creation, and the call to async on the future in the previous example is a NOOP.  But that is *not* the implication of the text (see below as well).  So, there are several points of dissonance here.  One is that the implication is we pass Task a coroutine and it *wraps* it in a Future.  But a Task *is* a Future.  So do we have a Future using another Future to wrap a coroutine, or what?  Another point of dissonance is that this phrasing implies that the *act* of wrapping the coroutine in a Future is what schedules it, yet when we introduced Future we apparently had to schedule it explicitly.  So I think there needs to be a mention of scheduling in the Future section.

But this then brings up the question of what exactly it is that Task does that differs from what a regular Future does, a question that is only partially answered by the documentation, because what 'scheduled' means for a regular Future isn't spelled out in the Future section.
  
Which I think means that what we really need is an overview document that puts all these concepts together into a conceptual framework, so that the documentation of the individual pieces makes sense.

As a followon point, the gloss on example of parallel execution of tasks says "A task is automatically scheduled for execution when it is created.  The event loop stops when all tasks are done."  This reads very strangely to me.  The first sentence seems to be pointing out the difference between this example and the previous one with Future where we had to explicitly schedule it (by calling async which creates a task...).  But it seems that that isn't true...so why is that sentence there? The second sentence presumably refers to the fact that run_until_complete runs the event loop until all scheduled tasks are complete..because they are wrapped in 'wait'.  But wait is not cross referenced or mentioned in the gloss, so I had to think about it carefully and look up wait to conclude that that was what it meant.

Of course, I could be more confused than necessary because I started reading with the 'task' chapter, but I don't see an overview chapter in the doc tree.
msg227453 - (view) Author: STINNER Victor (vstinner) * (Python committer) Date: 2014-09-24 14:27
I know that the "18.5.3. Tasks and coroutines" section of the documentation is probably the worst section :-( Feel free to suggest changes with a patch!

I started to enhance the documentation of the Task class, but there is still a lot of work to enhance the whole section.


> "We then see an example that appears to include scheduling a future via asyncio.async, because there is a specific mention of how we can attach a callback after it is scheduled but before the event loop is started."

I guess that you are talking about this example?
https://docs.python.org/dev/library/asyncio-task.html#example-future-with-run-until-complete

You cannot "schedule" a Future object. A Future object doesn't contain code. It only schedules callbacks when set_result() or set_exception() is called.

In this example, a call to the slow_operation coroutine function is scheduled: "slow_operation(future)" creates a coroutine object which is wrapped into a Task object. A coroutine is disconnected from the event loop. The role of the task is to schedule the execution of a coroutine object.

It becomes more complex when you know that the Task class inherits from the Future class :-/


> "I see that a Future is scheduled by its creation"

Again, this is wrong. You cannot "schedule a future". You can schedule a coroutine object by creating a task wrapping it.


> As a followon point, the gloss on example of parallel execution of tasks says "A task is automatically scheduled for execution when it is created.  The event loop stops when all tasks are done."  This reads very strangely to me.  The first sentence seems to be pointing out the difference between this example and the previous one with Future where we had to explicitly schedule it (by calling async which creates a task...).  But it seems that that isn't true...so why is that sentence there? The second sentence presumably refers to the fact that run_until_complete runs the event loop until all scheduled tasks are complete..because they are wrapped in 'wait'.  But wait is not cross referenced or mentioned in the gloss, so I had to think about it carefully and look up wait to conclude that that was what it meant.

Hum, I summarized too many information in "The event loop stops when all tasks are done." In fact, the example stops when run_until_complete() finished its job.
History
Date User Action Args
2014-09-24 14:50:01vstinnersetcomponents: + asyncio
2014-09-24 14:27:09vstinnersetmessages: + msg227453
2014-09-24 08:50:30pitrousetnosy: + gvanrossum, pitrou, vstinner, giampaolo.rodola, yselivanov
2014-09-24 01:34:04r.david.murraycreate