如何解决asyncio嵌套函数中的“This event loop is already running”错误
解决异步爬虫嵌套事件循环报错的方案
这个问题的核心在于你在已经运行的事件循环中再次调用了loop.run_until_complete()——asyncio不允许嵌套启动事件循环,这就是报错的原因。同时你内层函数的写法没利用好asyncio的原生异步机制,导致移除run_until_complete()后无法等待任务完成。下面是具体的修正方案和优化建议:
1. 修正内层异步函数
内层的f函数不需要手动获取事件循环并调用run_until_complete(),直接用await等待子任务集合即可,因为此时事件循环已经在main函数中运行,所有协程会被自动调度到同一个循环里。
修正后的f函数:
async def f(category, total): # 生成当前分类下的所有URL(假设原代码的t_list是total的元素,这里修正变量名对应) urls = [urls_template[category].format(t) for t in total] # 直接等待所有子任务完成,无需额外启动事件循环 result = await asyncio.gather(*map(parseURL_async, urls)) return result
2. 修正并优化main函数
原代码里存在变量名错误(比如把函数f覆盖成了task对象),同时推荐用更简洁的方式管理事件循环:
方式一:兼容Python 3.6及以下(手动管理loop)
def main(): loop = asyncio.get_event_loop() # 修正变量名,避免覆盖原函数f task_p = loop.create_task(f("p", all_p_list)) task_f = loop.create_task(f("f", all_f_list)) # 等待所有外层任务完成 loop.run_until_complete(asyncio.gather(task_p, task_f)) # 如果需要获取返回结果,可以改为: # result_p, result_f = loop.run_until_complete(asyncio.gather(task_p, task_f))
方式二:Python 3.7+推荐写法(用asyncio.run())
asyncio.run()会自动创建、运行和关闭事件循环,代码更简洁安全:
async def main(): # 创建异步任务 task_p = asyncio.create_task(f("p", all_p_list)) task_f = asyncio.create_task(f("f", all_f_list)) # 等待所有任务完成 await asyncio.gather(task_p, task_f) if __name__ == "__main__": asyncio.run(main())
额外优化建议
如果你的parseURL_async是基于同步请求库(比如requests)实现的,那其实并没有真正的异步能力。建议改用aiohttp这类异步HTTP库,才能真正发挥asyncio的并发优势,示例如下:
import aiohttp async def parseURL_async(url): async with aiohttp.ClientSession() as session: async with session.get(url) as resp: # 假设你需要解析HTML,这里可以用BeautifulSoup处理 html = await resp.text() return html # 返回解析后的结果
内容的提问来源于stack exchange,提问作者Blaszard
相关产品推荐
相关产品推荐

