Bienvenue sur IndexError.

Ici vous pouvez poser des questions sur Python et le Framework Django.

Mais aussi sur les technos front comme React, Angular, Typescript et Javascript en général.

Consultez la FAQ pour améliorer vos chances d'avoir des réponses à vos questions.

asyncio future avec future en callback

0 votes

Je souhaites ajouter à un objet future un callback qui est lui même à un objet future mais deux solutions se présentent avec deux problèmes:

  1. soit nous utilisons run_forever() et la loop tourne indéfiniment et ne s'arrête jamais car je ne sais pas dans quel ordre vont être joués les callback et donc quel callback va fermer la loop.
  2. soit nous utilisons rununtilcomplete(asyncio.gather(*tasks)), à ce moment là les tâches lancées s'exécutent mais la loop est détruite avant que les callback n'aient fini leur travail.

voici mon code :

class scenari():

            def __init__(self, **kwargs):
                self.future = asyncio.Future()
                self.kwargs = kwargs
                actions = ['action', 'url', 'data', 'parse', 'scenari']

                assert list(self.kwargs.keys()) == actions, \
                    "Votre scenari est malformé, " \
                    "il manque des informations " \
                    "{} doit être {}".format(list(self.kwargs.keys()), actions)

                for attr, value in kwargs.items():
                    if attr in actions:
                        setattr(self, attr, value)

            async def connect(self):
                '''
                Cette fonction permet se connecter à une page avec une methode get ou post
                Nous preparons les arguments pour qu'ils ne concernent que l'action à engager
                :return: 
                '''
                co = Connect(**{ key: value for key, value in self.kwargs.items() if key in ('action', 'url', 'data')})
                return await co.request()

            def callback_scenari(self, future):

                print(future.result())
                print('Nous sommes dans le callback')
                scenar = scenari(**self.kwargs['scenari'])
                asyncio.ensure_future(scenar.run())

            def print_fut(self, future):
                print(future.result())

            async def run(self):

                print('ok')
                self.future.add_done_callback((self.callback_scenari if self.kwargs['scenari']!=[] else self.print_fut))
                session, page = await self.connect()
                return self.future.set_result(Parse(page).list_parse(self.parse)) if self.parse \
                else self.future.set_result(page)

   def main_session(scenario):
           loop = asyncio.get_event_loop()
           tasks =  [ asyncio.ensure_future(scenari(loop=self.loop, **kwargs).run()) for kwargs in self.scenario ]
                    try:
                        loop.run_forever()
                        #loop.run_until_complete(asyncio.gather(*tasks))
                    finally:
                        loop.close()

main_session(scenario)

Au final j'aimerais interrompre la loop lorsqu'il n'y a plus d'événement à traiter. peut-être que je devrais faire cela sous forme de file d'attente ?

demandé 25-Oct par anonyme

1 Réponse

0 votes

Nous pouvons bien mettre un future en callback d'un autre future, il faut juste pouvoir gérer l'arrêt de la loop. J'ai créer un Counter qui compte le nombre de future créés, tant que le compte ne revient pas à 0 alors la loop n'est stoppée.

En réponse à moi-même et en simplifiant mon code:

class Counter()
    tasks = 0

class scenari ():
    ....
    def __init__(self, kwargs):
        self.future = asyncio.Future()
        Counter.tasks += 1

    def call_back_scenari(self, future):
        print(future.result())
        Counter.tasks -=1
        scenar = scenari(**self.kwargs['scenari'])
        asyncio.ensure_future(scenar.run())


    def exit_fut(self, future):
        print(future.result())
        Counter.tasks -=1
        if  Counter.tasks==0:
             self.loop.stop()


    async def run(self):
        # si un scenari est présent dans les kwargs alors nous l'envoyons en callback pour    refaire un réinstancier un objet scenari sinon
        # nous accedons à la methode exit_fut 
        self.future.add_done_callback((self.callback_scenari if kwargs['scenari']!=[] else self.exit_fut ))
        session, page = await self.connect() # connection à une page web
        self.future.set_result(parse(page)) # parse est une méthode pour parser une page web

## ici sont envoyées les tâches de bases
event = asyncio.ensure_future(scenari(loop=self.loop, kwargs).run())

def main():
    loop = asyncio.get_event_loop()
    try:
        loop.run_forever()
    except:
        loop.close()
répondu 26-Oct par torrak (168 points)

Si c'est ta question et que ta réponse re convient valide la.pour qu'on sache qu'elle est réglée

...