Jupyter中异步填充Pandas DataFrame遇RuntimeError问题求助
问题原因与解决方案
1. RuntimeError的直接原因
Jupyter Notebook(包括同类交互式Python环境)默认已经启动了一个asyncio事件循环,而asyncio.run()的设计目标是在无事件循环的环境中启动新循环。当你在已有运行中的循环里调用它时,就会触发这个错误——asyncio不允许嵌套运行事件循环。
2. 代码中的其他核心问题
除了事件循环冲突,你的代码还有一个关键问题:pandas.Series.apply()是同步方法,直接传入async函数fetch_status的话,不会等待协程执行完成,反而会返回一堆未执行的coroutine对象,根本拿不到实际的状态码。
修正后的完整代码
方式1:适配Jupyter环境的最简写法
import asyncio import pandas as pd import requests mydf = pd.DataFrame({'url':['https://google.com','https://apple.com']}) print(mydf) print("-----") async def fetch_status(url: str) -> int: # 用to_thread把同步的requests.get放到线程池执行,不阻塞事件循环 response = await asyncio.to_thread(requests.get, url) return response.status_code async def main_task() -> None: # 批量创建协程任务,替代无法处理async的apply方法 tasks = [fetch_status(url) for url in mydf['url']] # 等待所有任务完成,获取结果列表 status_codes = await asyncio.gather(*tasks) # 把结果赋值给新列 mydf['status'] = status_codes print(mydf) # Jupyter中直接用await运行协程,不需要asyncio.run() await main_task()
方式2:兼容Jupyter和普通脚本的通用写法
如果想让代码同时在Jupyter和普通Python脚本中运行,可以添加环境判断:
# 放在main_task函数定义之后 try: # 尝试获取当前已运行的事件循环 loop = asyncio.get_running_loop() if loop.is_running(): # Jupyter环境下直接await await main_task() except RuntimeError: # 无运行中的循环,用asyncio.run()启动 asyncio.run(main_task())
关键说明
- 放弃用
pandas.apply()处理async函数,改用asyncio.gather()批量执行协程,这是asyncio处理批量异步任务的标准方式。 - Jupyter中直接用
await关键字运行协程即可,无需调用asyncio.run()。 asyncio.to_thread()用来把同步的requests.get包装成可await的对象,避免阻塞事件循环;如果追求更原生的异步HTTP请求,可以改用aiohttp库。
内容的提问来源于stack exchange,提问作者Odyseus_v4
相关产品推荐
相关产品推荐

