Replies: 7 comments 7 replies
-
In fact, my code is more like this one, where I get the error every time:
|
Beta Was this translation helpful? Give feedback.
-
The program structure needs significant revision. Firstly the run statement asyncio.run(dummy()) is intended to start The I suggest you look at the tutorial to learn how to structure asyncio programs. The following works correctly: # -*- coding: utf-8 -*-
import time
import asyncio
import socket
async def recv(s):
while True:
try:
s.recvfrom(1024)
except OSError:
await asyncio.sleep(0)
class Pipo:
def __init__(self):
loop = asyncio.get_event_loop()
self._task1 = loop.create_task(self._loop1())
self._task2 = loop.create_task(self._loop2())
async def _loop1(self):
print("entering loop1")
while True:
try:
await asyncio.sleep(0.1)
except asyncio.CancelledError:
break
print("Pipo._loop1(): exiting")
async def _loop2(self):
print("entering loop2")
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
while True:
try:
await recv(s)
except asyncio.CancelledError:
break
print("Pipo._loop2(): exiting")
def stop(self):
print("Pipo.stop()")
self._task1.cancel()
self._task2.cancel()
class Blah:
def __init__(self):
self._pipo = Pipo()
def stop(self):
print("Blah.stop()")
self._pipo.stop()
print("Blah.stop(): all tasks stopped")
async def dummy():
blah = Blah()
try:
while True:
await asyncio.sleep(0)
finally:
blah.stop()
await asyncio.sleep(0) # Allow cancellation to take effect
raise
try:
asyncio.run(dummy())
except KeyboardInterrupt:
print("execution canceled (SIGTERM)")
finally:
asyncio.new_event_loop() |
Beta Was this translation helpful? Give feedback.
-
Apologies. My restructured program could be interrupted without error, but was not calling On further thought and testing, I think what you are trying to do is impossible. The following is my opinion - I'll do some further thinking/testing. The essence of the problem is a need to cancel tasks after a Given that I'd welcome any comments from others with experience of |
Beta Was this translation helpful? Give feedback.
-
Any idea why its works as expected on CPython but not on Micropython? |
Beta Was this translation helpful? Give feedback.
-
Just a comment as I tried the initial code posted (I was intending to copy @peterhinch example but I mistakenly copied the code of the first post), and it ran and cancelled the tasks. It did this several times without a problem until, as @fmafma indicates it stops with the traceback as was shown. Trying again a short time later and it worked and cancelled the tasks again, until it did not again :-) I was giving this a go to improve my understanding of asyncio. Reading the rational from Peter it all makes sense that if Ctrl C cancels the asyncio event loop then the tasks wont run and there's no point in cancelling them, but it does seem strange that using the original example code posted, sometimes the code will run to completion, and will cancel the tasks without any Traceback being issued. Maybe something to do with the current sequence that the program is executing when Ctrl C triggers the Terminate signal? But I guess that at the end of the day, what I've learn from this is that a Ctrl C will, in most cases, immediately stop the asynio event loop from running. |
Beta Was this translation helpful? Give feedback.
-
I encountered the same issue trying to do some cleanup after a keyboard interrupt. Sometimes the following code would raise import asyncio
import sys
loop = asyncio.get_event_loop()
task = loop.create_task(work())
try:
loop.run_until_complete(task)
finally:
if not task.done():
task.cancel() # This raises RuntimeError
try:
loop.run_until_complete(task)
except BaseException as e:
sys.print_exception(e)
asyncio.new_event_loop() I managed to get more predictable behaviour by setting import asyncio
import asyncio.core
loop = asyncio.get_event_loop()
task = loop.create_task(work())
try:
loop.run_until_complete(task)
finally:
if not task.done():
asyncio.core.cur_task = None # Reset current task
task.cancel()
try:
loop.run_until_complete(task)
except BaseException as e:
sys.print_exception(e)
asyncio.new_event_loop() This is still a hack, the |
Beta Was this translation helpful? Give feedback.
-
Just clear all tasks in import asyncio
async def worker(name):
await asyncio.sleep(10)
print(f"Worker: '{name}' done")
def sync_cancel_tasks():
"""
which is better?
creating a new queue and let the garbage collector do it's work?
asyncio.core._task_queue = asyncio.TaskQueue()
or popping all tasks and do not assign a new TaskQueue
"""
try:
while asyncio.core._task_queue.pop():
pass
except IndexError:
pass
async def main():
tasks = [asyncio.create_task(worker(f"Worker {n}")) for n in range(1, 5)]
print("submit now a CTRL+C to stop the event loop")
# will block until all tasks are finished
# if CTRL+C is submitted, the event loop stops
# the exception does not occour here, it occours at asyncio.run
await asyncio.gather(*tasks)
async def main2():
await asyncio.sleep(11)
print("Main 2 done")
try:
asyncio.run(main())
except KeyboardInterrupt:
# comment this out and the tasks will run
# after main2() is executed long enough by the event loop
sync_cancel_tasks()
# IndexError: empty heap
# print(asyncio.core._task_queue.pop())
...
print("Running now main2. If sync_calcel_tasks were not called, the old tasks from create_taks are executed also.")
asyncio.run(main2()) Output:
Output, if sync_cancel_taks is commented out:
|
Beta Was this translation helpful? Give feedback.
-
Hi!
In the follwoing code:
I sometimes get an error when I hit Ctrl-C (but not always):
Any idea what's going on?
Beta Was this translation helpful? Give feedback.
All reactions