2016-05-26 1 views
2

J'ai ce code pour tester comment fonctionne asyncio fonctionne:python asyncio gestionnaire des explications et des signaux

stop = False 


async def subcoro(): 
    # same result even with a range of 30 
    for i in range(30000): 
     pass 

async def first(): 
    global stop 
    while not stop: 
     await subcoro() 
     # without sleep no signal is triggered 
     await asyncio.sleep(0.1) 


async def main(loop): 
    coro = asyncio.ensure_future(first()) 
    await asyncio.wait([coro], loop=loop) 


def end(): 
    global stop 
    stop = True 


if __name__ == '__main__': 
    loop = asyncio.get_event_loop() 
    for signame in ('SIGINT', 'SIGTERM'): 
     loop.add_signal_handler(getattr(signal, signame), end) 
    try: 
     loop.run_until_complete(asyncio.ensure_future(main(loop))) 
    finally: 
     loop.close() 
     print('Bye!') 

Pourquoi j'ai à faire first() sommeils pendant un certain temps (même inférieur à 0,1) pour rendre la poignée de programme les signaux? Existe-t-il un autre moyen d'arrêter gracieusement toutes les coroutines et la boucle d'événements?

MISE À JOUR: Sur python-forum.org, ils m'ont dit de lire au PEP-0492 mais cela ne fournissait aucune solution ou suggestion.

MAJ2: Mon application réelle: https://github.com/FedericoTorsello/Embedded/tree/serialIO

+0

Pouvez-vous s'il vous plaît nous faire un exemple minimal, complet et vérifiable de votre problème à l'intérieur de votre question, s'il vous plaît? http://stackoverflow.com/help/mcve –

+0

Désolé, mais l'application dans le lien est assez 'minimale' (connectez-vous à arduino, définissez le thread du lecteur et exécutez coroutines). J'ai compris que le problème est l'appel à une fonction dans un autre thread qui lit les données de la série qui n'est pas bien gérée en boucle asyncio. Je vais essayer de passer à la serial.aio expérimentale de comprendre comment envelopper la fonction «write_line» dans une coroutine. – edoz90

Répondre

0

J'aime cette question, la première chose que j'ai essayé est de strace à la fois:

Avec le sleep je vois beaucoup de epoll (attendre le signal, qui est "retransmis" via une socket, typiquement pour se conformer à l'atomicité requise par le traitement d'un signal reçu).

Sans le sleep il n'y a pas de epoll, donc le signal est reçu par le processus, l'information est poussée sur le sochet, mais jamais lue.

Pourquoi est-ce? D'un point de vue sémantique, le:

while not stop: 
    await subcoro() 

est "incassable", au sens de

await de façon similaire à yield from, suspend l'exécution de [la] coroutine jusqu'à ce que [le] finalise awaitable et renvoie les données de résultat.

Mais comme subcoro ne rend pas la main à la boucle, il retournera « immédiatement », de sorte que le « attendent » est satisfaite et la boucle des boucles à nouveau, ne donnant jamais une chance pour la boucle principale pour attraper en haut Donc, vous êtes vraiment dans une "boucle infinie", ne remettant jamais la main à la boucle principale. Maintenant, avec le asyncio.sleep, vous redonnez la main à la boucle principale, comme évidemment, l'implémentation de asyncio.sleep le fait pour que la boucle principale puisse faire autre chose pendant la durée du sommeil, comme vérifier les événements réseau, comme le signal reçu sur les prises. Il y a une autre façon de donner explicitement revenir la main à la boucle, est un vide « rendement », comme:

@asyncio.coroutine 
def cooperate(): 
    yield 
    return 

maintenant appeler await cooperate() a le même effet que await asyncio.sleep(0.1) sans réellement dormir, ce qui est ce que asyncio.sleep fait quand donné une délai de 0:

@coroutine 
def sleep(delay, result=None, *, loop=None): 
    """Coroutine that completes after a given time (in seconds).""" 
    if delay == 0: 
     yield 
     return result 
    [...] 

d'un point de vue de la mise en œuvre, maintenant:

Avec le sommeil, asyncio.base_events.BaseEventLoop._run_once est appelé à plusieurs reprises, mais ne retourne jamais w sans le sleep, probablement parce que votre first ne retourne jamais à elle, je ne l'ai pas vérifié en profondeur.Pour conclure: subcoro n'a aucune signification en l'état, et dans une application du monde réel, il donnera un certain temps à la boucle principale, typiquement en appelant le réseau, ou en attendant quoi que ce soit.

+0

salut! Dans mon application réelle, 'subcoro' envoie des données post à un serveur avec aiohttp et ma' first' est lue dans une file d'attente de messages et appelle 'subcoro' (si le message doit être envoyé au serveur, sinon l'imprimer) . en regardant l'implémentation du sommeil Je pense que c'est la même chose mais je ne comprends pas pourquoi je dois l'utiliser pour arrêter l'exécution de la boucle: je veux dire ... ce n'est pas du tout pythonique. – edoz90

+0

Si votre subcoro 'attend' une requête réseau effectuée par' aiohttp' et que vous ne recevez toujours pas votre signal, merci de nous donner un exemple :-) –