【问题标题】:Asyncio event loop is closed when using asyncio.run()使用 asyncio.run() 时关闭 Asyncio 事件循环
【发布时间】:2021-12-02 10:09:24
【问题描述】:

我开始使用 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

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

【问题讨论】:

  • 你在什么操作系统上运行代码?
  • 我在 Windows 10,Python 3.8 上运行它
  • 您好像遇到了this issue。但是很可能您的代码实际上正在运行,尽管消息难看 - 您只是从 main() 返回内容而不打印它,因此除了消息之外没有输出 other。跨度>
  • 非常感谢!所以实际上是 aiohttp 引发了错误。我松了一口气,因为我不知道这个错误背后的原因
  • 不,它来自asyncio.ProactorEventLoop 相关的内部asyncio 组件,用于处理Windows 的IO 事件循环。我在异步 TCP 套接字服务器上遇到了同样的问题。

标签: python python-3.x python-asyncio


【解决方案1】:

更新

请考虑使用Trio 而不是 asyncio,后者更加稳定和一致。

import trio


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


trio.run(task) 

如果不能,最好在下面查看格雷格的答案

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 参数,可以放心忽略。

【讨论】:

  • 我试过这个,我确实没有得到错误。我希望这个答案得到足够的关注,因为从我所看到的情况来看,关于同一个问题有很多问题。谢谢!
  • 很高兴它有帮助。具有讽刺意味的是,我几个月来都无法通过我的 repo 解决这个问题 - 是时候实施这个变通方法了,看看这个解决方案是否也适用于套接字服务器。
  • 这是一个有趣的解决方案,我很喜欢。但是,与其手动关闭事件循环,不如直接设置策略?
  • 甚至不知道有它的选项 - 阅读文档后它说“因为 python 3.8 ProactorEventLoop 是 Windows 的默认值。”不知道为什么这个使用 IOCP 的错误循环是默认的,但我也担心违背开发者的决定。
  • 惊讶地看到它运行流畅,感谢提示!
【解决方案2】:

虽然这已得到回答和接受。你可以用一行代码解决这个问题: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())

【讨论】:

    猜你喜欢
    • 2020-08-15
    • 1970-01-01
    • 2018-10-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多