Veuillez expliquer “la Tâche a été détruit, mais il est en attente!”
Python 3.4.2
Je suis en train d'apprendre asyncio et je l'utilise pour la permanence d'écouter de la CIB en bus, tandis que gbulb à l'écoute de la dbus.
Quelques remarques:
J'ai donc créé une fonction listen_to_ipc_channel_layer
que la permanence d'écoute pour les messages entrants sur la CIB canal et passe le message à un message_handler
.
Je suis également à l'écoute de SIGTERM et SIGINT. Alors quand j'ai envoyer un signal SIGTERM à l'python processus en cours d'exécution le code que vous trouverez au bas, le script doit se terminer normalement.
Le problème
... Je vais avoir est l'avertissement suivant:
got signal 15: exit
Task was destroyed but it is pending!
task: <Task pending coro=<listen_to_ipc_channel_layer() running at /opt/mainloop-test.py:23> wait_for=<Future cancelled>>
Process finished with exit code 0
... avec le code suivant:
import asyncio
import gbulb
import signal
import asgi_ipc as asgi
def main():
asyncio.async(listen_to_ipc_channel_layer())
loop = asyncio.get_event_loop()
for sig in (signal.SIGINT, signal.SIGTERM):
loop.add_signal_handler(sig, ask_exit)
# Start listening on the Linux IPC bus for incoming messages
loop.run_forever()
loop.close()
@asyncio.coroutine
def listen_to_ipc_channel_layer():
"""Listens to the Linux IPC bus for messages"""
while True:
message_handler(message=channel_layer.receive(["my_channel"]))
try:
yield from asyncio.sleep(0.1)
except asyncio.CancelledError:
break
def ask_exit():
loop = asyncio.get_event_loop()
for task in asyncio.Task.all_tasks():
task.cancel()
loop.stop()
if __name__ == "__main__":
gbulb.install()
# Connect to the IPC bus
channel_layer = asgi.IPCChannelLayer(prefix="my_channel")
main()
Encore je ne comprends que très peu de asyncio, mais je pense que je sais ce qui se passe. En attendant yield from asyncio.sleep(0.1)
le gestionnaire de signal pris la SIGTERM et dans ce processus, il appelle task.cancel()
.
Question jeté dans: Ne devrait pas déclencher la CancelledError
dans le while True:
boucle? (Parce qu'il ne l'est pas, mais c'est comme ça que je comprends "L'appel de l'annuler() va lancer une CancelledError à la enveloppé coroutine").
Finalement loop.stop()
est appelé, ce qui arrête la boucle, sans attendre que soit yield from asyncio.sleep(0.1)
pour retourner un résultat ou même l'ensemble de la coroutine listen_to_ipc_channel_layer
.
S'il vous plaît corrigez-moi si je me trompe.
Je pense que la seule chose que je dois faire est de faire de mon programme d'attendre le yield from asyncio.sleep(0.1)
pour retourner un résultat et/ou coroutine de sortir le tout en boucle et terminer.
Je crois que je confonds beaucoup de choses. Merci de m'aider à faire ces choses afin que je puisse comprendre comment gracieusement fermer la boucle d'événement sans avertissement.
OriginalL'auteur Daniel | 2016-11-30
Vous devez vous connecter pour publier un commentaire.
Le problème vient de la fermeture de la boucle immédiatement après l'annulation de tâches. Comme le annuler() les docs de l'état
Prendre cet extrait de code:
Avis
ask_exit
annule les tâches mais n'est passtop
la boucle, sur le prochain cycle delooping_coro()
l'arrête. La sortie si vous annulez c'est:Avis comment
pending_doom
annule et arrête la boucle immédiatement après. Si vous le laisser fonctionner jusqu'à ce que lepending_doom
coroutines se réveille du sommeil, vous pouvez voir le message d'avertissement que vous obtenez:loop.close()
à la fin.OriginalL'auteur Yeray Diaz Diaz
Le sens de la question est que une boucle n'a pas le temps de terminer toutes les tâches.
Il n'y a aucune chance de faire un "nouveau cycle" de la boucle dans votre approche. Pour le faire correctement, vous devez déplacer un arrêt de l'exploitation à un espace non-cyclique coroutine à donner votre boucle une chance à la fin.
Deuxième chose importante est
CancelledError
sensibilisation.Donc, après le nettoyage de votre coroutine doit soulever
CancelledError
à être marqué comme annulée.À l'aide d'un extra coroutine pour arrêter la boucle n'est pas un problème car elle n'est pas cyclique, et doit être fait immédiatement après l'exécution.
OriginalL'auteur I159