【问题标题】:Necessity of closing asyncio event loop explicitly显式关闭异步事件循环的必要性
【发布时间】:2016-12-19 21:34:36
【问题描述】:

故事:

我目前正在浏览asyncio basic examples,尤其是this one——最简单的HTTP 客户端。 main函数启动一个事件循环,一直运行到数据获取完成,然后关闭事件循环:

def main():
    loop = get_event_loop()
    try:
        body = loop.run_until_complete(fetch())
    finally:
        loop.close()
    print(body.decode('latin-1'), end='')

但是,如果我省略 loop.close(),代码也可以工作:

def main():
    loop = get_event_loop()
    body = loop.run_until_complete(fetch())
    print(body.decode('latin-1'), end='')

问题:

虽然有一个示例,但问题是一个通用问题 - 如果忘记关闭 asyncio 事件循环,可能会出现什么问题?事件循环会一直隐式关闭吗?

【问题讨论】:

  • 你会泄露资源。
  • 你认为什么是隐式关闭它?我认为你只能在程序结束时依赖垃圾收集,你的程序在完成事件循环后运行多长时间直到程序结束?
  • @FilipHaglund 谢谢。你能想出一种方法来测试/证明吗?
  • (请记住,link you have supplied 用于 python 3.3 的异步,not updated 用于 python 3.5/3.6。)

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


【解决方案1】:

.close() 可以被不同的事件循环实现用来释放循环分配的系统资源(或做任何其他事情)。如果您查看_UnixSelectorEventLoop 的代码,它是Linux 中使用的(默认)IOLoop,您会发现以下代码:

def close(self):
    super().close()
    for sig in list(self._signal_handlers):
        self.remove_signal_handler(sig)

这里,例如,close() 删除用loop.add_signal_handler() 注册的信号处理程序。

由于可以在不同的线程上启动多个 IOLoop,或者在关闭旧的 IOLoop 后可以创建新的 IOLoop,(请参阅asyncio.new_event_loop()),因此应将关闭它们视为一个好习惯。

更新

从 Python 3.7 开始,建议使用 asyncio.run 而不是 run_until_complete()

# Python 3.7+
def main():
    body = asyncio.run(fetch())
    print(body.decode('latin-1'), end='')

除其他外,asyncio.run 负责处理 finally close() 循环。

【讨论】:

猜你喜欢
  • 1970-01-01
  • 2020-12-08
  • 2022-07-15
  • 1970-01-01
  • 2013-09-01
  • 2017-07-07
  • 1970-01-01
  • 2015-06-09
相关资源
最近更新 更多