Asyncio event loop is closed when using asyncio.run()

Viewed 2817

I'm getting started to AsyncIO and AioHTTP, and i'm writing some basic code to get familiar with the syntax. I tried the following code that should perform 3 requests concurrently:

import time
import logging
import asyncio
import aiohttp
import json
from aiohttp import ClientSession, ClientResponseError
from aiocfscrape import CloudflareScraper

async def nested(url):
    async with CloudflareScraper() as session:
        async with session.get(url) as resp:
            return await resp.text()

async def main():
    URL = "https://www.binance.com/api/v3/exchangeInfo"
    await asyncio.gather(nested(URL), nested(URL), nested(URL))

asyncio.run(main())

Here is the output:

raise RuntimeError('Event loop is closed')
RuntimeError: Event loop is closed

I don't understand why do i get that error, can anyone help me on this?

2 Answers

Update

Please consider using Trio over asyncio, which is much more stable and consistent.

import trio


async def task():
    await trio.sleep(5)


trio.run(task) 

If can't, prefer checking Greg's answer below

import asyncio
import sys

if sys.platform:
    asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())

Original post

I've finally figured out how to keep ProactorEventLoop running, preventing unsuccessful IO closure.

Really not sure why windows' Event loop is so faulty, as this also happens for asyncio.open_connection and asyncio.start_server.

To workaround this, you need to run event loop in forever loop and close manually.

Following code will cover both windows and other environments.

import asyncio
from aiocfscrape import CloudflareScraper


async def nested(url):
    async with CloudflareScraper() as session:
        async with session.get(url) as resp:
            return await resp.text()


async def main():
    await nested("https://www.binance.com/api/v3/exchangeInfo")


try:
    assert isinstance(loop := asyncio.new_event_loop(), asyncio.ProactorEventLoop)
    # No ProactorEventLoop is in asyncio on other OS, will raise AttributeError in that case.

except (AssertionError, AttributeError):
    asyncio.run(main())
    
else:
    async def proactor_wrap(loop_: asyncio.ProactorEventLoop, fut: asyncio.coroutines):
        await fut
        loop_.stop()

    loop.create_task(proactor_wrap(loop, main()))
    loop.run_forever()

This code will check if new EventLoop is ProactorEventLoop.
If so, keep loop forever until proactor_wrap awaits main and schedules loop stop.

Else - possibly all other OS than Windows - doesn't need these additional steps, simply call asyncio.run() instead.

IDE like Pycharm will complain about passing AbstractEventLoop to ProactorEventLoop parameter, safe to ignore.

Whilst this has been answered and accepted. You can fix this issue with one line of code: asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())

Event loop is closed is a known issue on Windows (see https://github.com/encode/httpx/issues/914). I suspect this will be fixed in later versions of Python. To get around the error, simply set the event loop policy to WindowsSelectorEventLoopPolicy.

If you plan to run the code on non-windows environment; then you'll want to either add an if statement to prevent error. E.g: if sys.platform == 'win32'. Or add code to set the policies.

Working example:

import asyncio
from aiocfscrape import CloudflareScraper
import sys

async def nested(url):
    async with CloudflareScraper() as session:
        async with session.get(url) as resp:
            print(resp.status)
            return await resp.text()

async def main():
    URL = "https://www.binance.com/api/v3/exchangeInfo"
    await asyncio.gather(nested(URL), nested(URL), nested(URL))

# Only preform check if your code will run on non-windows environments.
if sys.platform == 'win32':
    # Set the policy to prevent "Event loop is closed" error on Windows - https://github.com/encode/httpx/issues/914
    asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())

asyncio.run(main())
Related