Why does this asyncio.Task never complete the undo?

If I ran this in the python3 interpreter:

import asyncio @asyncio.coroutine def wait(n): asyncio.sleep(n) loop = asyncio.get_event_loop() fut = asyncio.async(wait(10)) fut.add_done_callback(lambda x: print('Done')) asyncio.Task.all_tasks() 

I get the following result:

 {<Task pending coro=<coro() running at /usr/local/Cellar/python3/3.4.3/Frameworks/Python.framework/Versions/3.4/lib/python3.4/asyncio/coroutines.py:139> cb=[<lambda>() at <ipython-input-5-c72c2da2ffa4>:1]>} 

Now, if I run fut.cancel() , I return True . But typing fut returns a view of the task that it cancels:

 <Task cancelling coro=<coro() running at /usr/local/Cellar/python3/3.4.3/Frameworks/Python.framework/Versions/3.4/lib/python3.4/asyncio/coroutines.py:139> cb=[<lambda>() at <ipython-input-5-c72c2da2ffa4>:1]> 

And the task is never canceled ( fut.cancelled() never returns True )

Why doesn't he cancel?

+4
source share
2 answers

The call to task.cancel() intended only for specifying a task that will be canceled the next time the event loop starts; it does not immediately cancel the task, or even guarantee that the task will actually be canceled when the event loop begins its next iteration. All this is described in the documentation :

cancel ()

Request this task to cancel itself.

This orders for the CancelledError , which should be thrown into the wrapped coroutines in the next loop through the event loop. Then coroutine has the ability to clear or even reject the request using try / except / finally.

Unlike Future.cancel() , this does not guarantee that the task will be canceled: an exception can be caught and accepted, delayed cancellation of the task or prevention of cancellation completely. a task may also return a value or raise another exception.

Immediately after calling this method, cancelled() will not return True (if the task has not been canceled). The task will be marked as canceled when the wrapped coroutine completes using the CancelledError exception (even if cancel() not called).

In your case, you never start the event loop, so the task is never canceled. You will need to call loop.run_until_complete(fut) (or loop.run_forever() , although this is not the best choice for this particular case) to really cancel the task.

Also, for what's worth it, it is usually easier to test asyncio code using actual scripts rather than an interpreter, as it tends to get tired to constantly rewrite coroutines and start / stop the event loop.

+4
source

Asynchronous testing in the interpreter is difficult because python must constantly monitor the event loop.

So, some tips for testing asyncio:

  • Write and run scripts instead of using an interactive interpreter
  • Add loop.run_forever() at the end of the script so that all tasks are completed.
  • An alternative is to run loop.run_until_complete(coro()) for each task you want to run.
  • Have yield from before asyncio.sleep(n) so that it can be started. The current code returns the generator and does nothing.
0
source

All Articles