Runtimeerror: This Event Loop Is Already Running in Python

Python RuntimeError: This event loop is already running

loop.run_until_complete() already runs your loop 'forever'.

Instead of firing of your listen_for_message() awaitable as a task, just await on it. That then runs forever, because listen_for_message() itself never returns:

async def my_app():
websocket = await connect_to_dealer()
await listen_for_message(websocket)

if __name__ == '__main__':
loop = asyncio.get_event_loop()
loop.run_until_complete(my_app())

Note that your connect_to_dealer() function doesn't return the websocket; that's probably an oversight you want to correct:

async def connect_to_dealer():
return await websockets.connect(websocketadress)

I removed the hello_message = await websocket.recv() / print(hello_message) lines there because listen_for_message() will already receive messages and print them.

RuntimeError: This event loop is already running when combine asyncio and aiohttp

I find the answer, from aiohttp source code:

  • web.run_app(app) works as next:
async def _run_app(......):

runner = AppRunner(
app,
handle_signals=handle_signals,
access_log_class=access_log_class,
access_log_format=access_log_format,
access_log=access_log,
)

await runner.setup()
......
while True:
await asyncio.sleep(delay)

def run_app(......):

loop = asyncio.get_event_loop()
try:
main_task = loop.create_task(
_run_app(
app,
......
)
)
loop.run_until_complete(main_task)

But it will directly call loop.run_until_complete which makes us not possible for us to start our own event loop which used by asyncio.run() in main program.

  • To conquer this, we should use some low-level functions as next:
import asyncio
from aiohttp import web

async def handle(request):
name = request.match_info.get('name', "Anonymous")
text = "Hello, " + name
return web.Response(text=text)

async def start_api_server():
print("api")
loop = asyncio.get_event_loop()
app = web.Application()
app.add_routes([web.get('/', handle),
web.get('/{name}', handle)])
#web.run_app(app)
runner = web.AppRunner(app)
await runner.setup()
await loop.create_server(runner.server, '127.0.0.1', 8080)
print('Server started at http://127.0.0.1:8080...')

async def action():
print("action")
await asyncio.sleep(10000)

async def main():
#await action()
await(asyncio.gather(start_api_server(), action()))

if __name__ == '__main__':
asyncio.run(main())

Above code reproduce the runner setup in web.run_app, and pass the property server in AppRunner to asyncio.create_server to new a aiohttp server. Then could reuse the eventloop in asyncio.run to meet my requirement.

How can I deal with This event loop is already running error on a nested function in asyncio?

How can I deal with the problem and run the loop?

The loop is already running. You don't need to (and can't) run it again.

result = await loop.run_until_complete(asyncio.gather(*soups_coro))

You're awaiting the wrong thing. loop.run_until_complete doesn't return something you can await (a Future); it returns the result of whatever you're running until completion.

The reason nothing appears to happen when you call f directly is that f is an asyncio-style coroutine. As such it returns a future that must be scheduled with the event loop. It doesn't execute until a running event loop tells it to. loop.run_until_complete takes care of all of that for you.

To wrap up your question, you want to await asyncio.gather.

async def f(category, total): 
urls = [urls_template[category].format(t) for t in t_list]
soups_coro = map(parseURL_async, urls)

result = await asyncio.gather(*soups_coro)

And you probably also want to include return result at the end of f, too.



Related Topics



Leave a reply



Submit