使用asyncio.run()时关闭Asyncio事件循环

2022-03-25 00:00:00 python python-3.x python-asyncio

问题描述

我正在开始使用AsyncIO和AioHTTP,并且我正在编写一些基本代码来熟悉语法。我尝试了以下应同时执行3个请求的代码:

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())

以下是输出:

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

我不明白为什么会出现该错误,有人能帮我解决这个问题吗?


解决方案

更新

请考虑使用Trio而不是异步,这样更稳定、更一致。

import trio


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


trio.run(task) 

如果不能回答,请检查下面Greg的答案

import asyncio
import sys

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

原始帖子

我终于知道如何保持ProactorEventLoop运行,防止IO关闭失败。

我真的不确定为什么Windows的事件循环如此错误,因为asyncio.open_connectionasyncio.start_server也会发生这种情况。

若要解决此问题,您需要在永久循环中运行事件循环并手动关闭。

以下代码将涵盖Windows和其他环境。

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()
此代码将检查新的EventLoop是否为ProactorEventLoop
如果是,则一直保持循环,直到proactor_wrap等待main并计划停止循环。

否则-可能是Windows以外的所有其他操作系统-不需要这些额外步骤,只需调用asyncio.run()即可。

像PyCharm这样的IDE会抱怨将AbstractEventLoop传递给ProactorEventLoop参数,可以安全地忽略。

相关文章