Issue
I use a coroutine to add another coroutine to the event loop multiple times but partway through I cancel the first coroutine. I thought this would mean that any coroutines already added to the event loop would complete successfully and no more would be added, however I find that coroutines that have already been added to the event loop also seem to be cancelled.
I'm running this script in Spyder so I don't need to call run_until_complete, etc. because the event loop is already running in the background on my environment.
I'm sure I'm missing something and the code is behaving exactly as it should - but I can't figure out why. I would also like to know how I might allow cancellation of runTimes but still let slowPrinter complete.
Thank you!
Code below
import asyncio
loop = asyncio.get_event_loop()
async def runTimes(async_func, times):
for i in range(0, times):
task = loop.create_task(async_func())
await task
async def slowPrinter():
await asyncio.sleep(2)
print("slowPrinter done")
async def doStuff():
for i in range(0, 10):
await(asyncio.sleep(1))
print("doStuff done")
async def doLater(delay_ms, method, *args, **kwargs):
try:
print("doLater " + str(delay_ms) + " " + str(method.__name__))
except AttributeError:
print("doLater " + str(delay_ms))
await asyncio.sleep(delay_ms/1000)
method(*args, **kwargs)
print("doLater complete")
task = loop.create_task(runTimes(slowPrinter, 3))
loop.create_task(doLater(3000, task.cancel))
loop.create_task(doStuff())
Output
doLater 3000 cancel
slowPrinter done
doLater complete
doStuff done
Expected Output
doLater 3000 cancel
slowPrinter done
doLater complete
**slowPrinter done**
doStuff done
Edit: Part of the reason I have built the code without using things like run_later is because I need to port the code to micropython later so I am sticking to functions I can use on micropython.
Edit2: Interestingly, task cancellation seems to propagate to tasks created from within the coroutine as well!
async def runTimes(async_func, times):
for i in range(0, times):
task = loop.create_task(async_func())
try:
await task
except asyncio.CancelledError:
print("cancelled as well")
Output
doLater 3000 cancel
slowPrinter done
doLater complete
cancelled as well
slowPrinter done
doStuff done
Solution
That's because your task is waiting on another task:
async def runTimes(async_func, times):
for i in range(0, times):
task = loop.create_task(async_func())
await task ## HERE!
As per asyncio's documentation:
To cancel a running Task use the cancel() method. Calling it will cause the Task to throw a CancelledError exception into the wrapped coroutine. If a coroutine is awaiting on a Future object during cancellation, the Future object will be cancelled.
You may have to look for a way to prevent the task from being cancelled while waiting.
Answered By - ichramm
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.