145 votes

asyncio.run () ne peut pas être appelé à partir d'une boucle d'événements en cours d'exécution

Je voudrais utiliser asyncio pour obtenir le html de la page Web.

J'exécute le code suivant dans le notebook jupyter:

 import aiofiles
import aiohttp
from aiohttp import ClientSession

async def get_info(url, session):
    resp = await session.request(method="GET", url=url)
    resp.raise_for_status()
    html = await resp.text(encoding='GB18030')
    with open('test_asyncio.html', 'w', encoding='utf-8-sig') as f:
        f.write(html)
    return html
    
async def main(urls):
    async with ClientSession() as session:
        tasks = [get_info(url, session) for url in urls]
        return await asyncio.gather(*tasks)

if __name__ == "__main__":
    url = ['http://huanyuntianxiazh.fang.com/house/1010123799/housedetail.htm', 'http://zhaoshangyonghefu010.fang.com/house/1010126863/housedetail.htm']
    result = asyncio.run(main(url))

Cependant, il renvoie RuntimeError: asyncio.run() cannot be called from a running event loop

Quel est le problème?

Comment le résoudre?

67voto

Jean Monet Points 621

A ajouter à la cglacet - si l'on veut détecter si une boucle est en cours d'exécution et ajuster automatiquement (ie exécuter main() sur la boucle existante, sinon asyncio.run() ), voici une suggestion que j'ai essayée ( si en effet on veut faire ça ):

 try:
    loop = asyncio.get_running_loop()
except RuntimeError:  # if cleanup: 'RuntimeError: There is no current event loop..'
    loop = None

if loop and loop.is_running():
    print('Async event loop already running')
    tsk = loop.create_task(main())
    # ^-- https://docs.python.org/3/library/asyncio-task.html#task-object
    tsk.add_done_callback(                                          # optional
        lambda t: print(f'Task done: '                              # optional
                        f'{t.result()=} << return val of main()'))  # optional (using py38)
else:
    print('Starting new event loop')
    asyncio.run(main())

37voto

vgoklani Points 574

Utilisez simplement ceci:

https://github.com/erdewit/nest_asyncio

 import nest_asyncio
nest_asyncio.apply()

25voto

Mark Points 494

En combinant les méthodes de Pankaj Sharma et Jean Monet, j'ai écrit l'extrait suivant qui agit comme asyncio.run (avec une syntaxe légèrement différente), mais fonctionne également dans un notebook Jupyter.

 class RunThread(threading.Thread):
    def __init__(self, func, args, kwargs):
        self.func = func
        self.args = args
        self.kwargs = kwargs
        super().__init__()

    def run(self):
        self.result = asyncio.run(self.func(*self.args, **self.kwargs))

def run_async(func, *args, **kwargs):
    try:
        loop = asyncio.get_running_loop()
    except RuntimeError:
        loop = None
    if loop and loop.is_running():
        thread = RunThread(func, args, kwargs)
        thread.start()
        thread.join()
        return thread.result
    else:
        return asyncio.run(func(*args, **kwargs))

Usage:

 async def test(name):
    await asyncio.sleep(5)
    return f"hello {name}"

run_async(test, "user")  # blocks for 5 seconds and returns "hello user"

1voto

Pankaj Sharma Points 1052

Comme cglacet l'a mentionné, la documentation dit

Cette fonction ne peut pas être appelée lorsqu'une autre boucle d'événement asyncio est fonctionnant dans le même fil.

Vous pouvez utiliser un autre thread ie -

 class ResolveThread(threading.Thread):
            def __init__(self,result1,fun,url):
                self.result1= result1
                self.fun = fun
                self.url = url
                threading.Thread.__init__(self)
            def run(self):
                result1[0] = asyncio.run(self.fun(self.url))


result1 = [None]
sp = ResolveThread(result1)
sp.start()
sp.join() # connect main thread
result = result1[0]

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X