我开始使用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
我不明白为什么会收到该错误,有人可以帮我吗?
答案 0 :(得分:7)
我终于弄清楚了如何使ProactorEventLoop
保持运行状态,以防止IO关闭失败。
真的不确定Windows的事件循环为什么如此错误,因为asyncio.open_connection
和asyncio.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
参数,可以忽略。
答案 1 :(得分:1)
这已被回答并被接受。您可以使用以下一行代码来解决此问题:asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())
Event loop is closed
是Windows上的一个已知问题(请参阅https://github.com/encode/httpx/issues/914)。我怀疑这将在更高版本的Python中修复。要解决该错误,只需将事件循环策略设置为WindowsSelectorEventLoopPolicy。
如果您打算在非Windows环境中运行代码;那么您将想要添加一个if语句以防止错误。例如:if sys.platform == 'win32'
。或添加代码以设置策略。
工作示例:
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())