Python异步函数致Jupyter Notebook内核崩溃问题求助
可能的原因及解决办法
1. asyncio.run 与 Jupyter 事件循环的冲突
Jupyter Notebook本身已经维护着一个asyncio事件循环,而asyncio.run()会创建全新的独立循环,再加上nest_asyncio.apply()修改了原有循环的嵌套规则,两种循环的状态容易发生冲突,最终导致内核崩溃。
解决办法:
直接在Jupyter单元格中await异步函数,无需调用asyncio.run()或手动获取循环执行。Jupyter支持在交互环境中直接执行异步代码:
# 移除 nest_asyncio.apply() 和 asyncio.run() async def fetch_url(session, url): async with session.get(url, timeout=aiohttp.ClientTimeout(total=10)) as response: return await response.text() async def gather_fetched_urls(urls): async with aiohttp.ClientSession() as session: tasks = [fetch_url(session, url) for url in urls] # 无需 ensure_future,asyncio.gather 可直接接收协程 results = await asyncio.gather(*tasks, return_exceptions=True) return results URLs_list = ["你的API地址1", "你的API地址2"] responses = await gather_fetched_urls(URLs_list)
2. 未处理的请求异常
如果某个API请求抛出异常(比如超时、连接失败、HTTP错误),asyncio.gather()默认会直接抛出异常,而Jupyter内核对未捕获的异步异常处理不够健壮,可能触发内核崩溃。
解决办法:
给asyncio.gather()添加return_exceptions=True参数,将异常作为结果返回,避免整个任务链崩溃;同时给请求添加超时时间,防止请求无限挂起:
async def fetch_url(session, url): try: async with session.get(url, timeout=aiohttp.ClientTimeout(total=10)) as response: response.raise_for_status() # 捕获HTTP错误(比如404、500) return await response.text() except Exception as e: return f"请求失败: {str(e)}"
3. nest_asyncio 的潜在副作用
nest_asyncio.apply()会修改asyncio的核心循环逻辑,允许嵌套运行事件循环,但这种修改可能和Jupyter的循环管理机制不兼容,尤其是在资源清理阶段(比如ClientSession关闭时),容易引发循环状态混乱。
解决办法:
只有在确实需要嵌套运行循环时才使用nest_asyncio,如果只是在Jupyter单元格中执行单次异步任务,完全不需要调用它。
4. 资源泄漏
如果请求数量过大,或者任务没有被正确回收,可能导致内存耗尽或文件句柄泄漏,最终让内核崩溃。
解决办法:
- 控制并发请求数量:使用
asyncio.Semaphore限制同时发起的请求数,避免一次性创建过多任务压垮系统:
async def gather_fetched_urls(urls): semaphore = asyncio.Semaphore(10) # 限制最多10个并发请求 async def bounded_fetch(url): async with semaphore: async with aiohttp.ClientSession() as session: return await fetch_url(session, url) tasks = [bounded_fetch(url) for url in urls] results = await asyncio.gather(*tasks, return_exceptions=True) return results
- 确保所有
ClientSession都通过async with正确关闭,避免资源泄漏。
内容的提问来源于stack exchange,提问作者Augusto
相关产品推荐
相关产品推荐

