You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python asyncio切换事件循环报错‘Event loop is closed’求助

解决asyncio循环关闭引发的"Event loop is closed"错误

兄弟我太懂这种被asyncio的循环问题逼疯的感觉了😅,从你给出的报错信息和代码来看,问题的根源其实和你频繁创建销毁事件循环,再加上第三方库(ccxt)的资源清理逻辑有关,咱们一步步拆解:

问题核心分析

从报错栈能看到,是ccxt的Exchange.__del__方法在尝试调用self.asyncio_loop.run_until_complete(self.session.close())时,发现事件循环已经被关闭了。为什么会概率性出现?因为Python的垃圾回收(GC)时机不确定:有时候Exchange对象在你关闭循环前就被回收了,没问题;但更多时候它会留在内存里,等你关闭旧循环、创建新循环之后才被GC,这时候它持有的旧循环引用已经失效,就触发了错误。

而你原来的写法里,每次循环都创建、关闭事件循环是完全没必要的——asyncio的事件循环设计就是用来复用的,频繁销毁重建反而会导致异步资源的生命周期和循环绑定出问题。

具体解决方案

1. 复用事件循环,不要每次循环都重建

把事件循环的创建和关闭逻辑移到整个targetData循环的外面,用一个事件循环处理所有异步任务,这是asyncio的标准用法:

import asyncio

# 把单条数据的处理逻辑封装成协程
async def process_single_data(data):
    # 异步加载graph
    graph = await load_graph(data)
    paths = bellman_ford(graph, unique_paths=True)
    
    for path in paths:
        try:
            print_opportunity_for_path(graph, path)
        except Exception as exc:
            print(f'Error: {exc}')
    
    # 如果需要等待1秒,用asyncio.sleep(这才是正确的异步等待方式)
    await asyncio.sleep(1)

# 主协程,遍历所有数据
async def main():
    for data in targetData:
        await process_single_data(data)

if __name__ == "__main__":
    loop = asyncio.get_event_loop()
    try:
        # 用一个循环跑完所有任务
        loop.run_until_complete(main())
    finally:
        # 所有任务完成后再关闭循环
        loop.close()

2. 显式清理ccxt的异步资源

ccxt的异步Exchange对象依赖事件循环来关闭内部的ClientSession,不要依赖它的__del__方法自动清理(因为__del__的执行时机不可控),要在使用完后显式调用await exchange.close():

比如在你的load_graph函数里,应该这样处理:

async def load_graph(data):
    # 创建ccxt异步实例
    exchange = ccxt.async.gdax()
    try:
        # 这里写你的业务逻辑,比如获取交易对数据、构建graph
        # ...
        return graph
    finally:
        # 显式关闭exchange,确保session在循环关闭前就清理完毕
        await exchange.close()

3. 修正错误的异步等待写法

你原来代码里的asyncio.wait(1)是错误用法:asyncio.wait是用来等待一组协程完成的API,要实现“等待1秒”的效果,应该用await asyncio.sleep(1),而且必须放在协程函数内部执行。

为什么原来的写法会出问题?

  1. 频繁创建销毁事件循环,打破了异步资源(比如ccxt的session、连接)和循环的生命周期绑定;
  2. 依赖第三方库的__del__方法清理资源,但__del__的执行时机由GC决定,大概率会在你关闭旧循环之后才触发,导致它尝试用已关闭的循环执行异步操作;
  3. 错误使用asyncio.wait,没有正确实现异步等待逻辑。

按照上面的方案修改后,应该就能彻底解决这个概率性报错的问题了!

内容的提问来源于stack exchange,提问作者Isaiah Y

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 09:01:42