更新
最初我推荐下面Greg的答案:
import asyncio
import sys
if sys.platform:
asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())
结果表明,使用 WindowsSelectorEventLoop
存在以下功能问题:
- 无法支持超过 512 个套接字
- 无法使用管道
- 无法使用子进程
这是因为 Windows 使用 I/O 完成端口,而不像 *nix - 因此 SelectorEventLoop
不适用于 Windows,也没有完全实现。
如果这些限制对您很重要 - 您可能最好使用本答案中的冗长解决方法。
请查看有关差异的更多信息,请访问文档。
或者,考虑使用 Trio 而不是 asyncio,它更加稳定和一致。
import trio
async def task():
await trio.sleep(5)
trio.run(task)
原始帖子
我终于找到了如何保持 ProactorEventLoop
运行,防止 IO 关闭失败。
真的不知道为什么 Windows 的事件循环这么有问题,因为这也会发生在 asyncio.open_connection
和 asyncio.start_server
上。
为了解决这个问题,你需要在 forever 循环中运行事件循环,并手动关闭。
下面的代码将覆盖 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)
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
参数,可以放心忽略。
try-except
来抑制单个RuntimeError
,无论捕获块放在哪里。 - jupiterbjy