Python异步函数运行异常:程序无法终止,停滞在索引输出阶段
问题分析与解决方案
程序状态判断
打印完所有链接索引后停滞,程序大概率仍在运行,但处于低效执行或等待异常请求完成的状态,不建议无限制等待,需要排查代码问题。
核心问题点
1. 低效的索引查找
links.index(link) 是O(n)复杂度的操作,100k次循环会导致总时间复杂度达到O(n²),这会让索引打印阶段就消耗大量时间,甚至让你误以为请求阶段已经开始,实际任务还在排队执行查找操作。
2. 一次性创建100k异步任务
直接为100k链接创建全部任务会导致事件循环过载,即便有httpx的连接限制,大量待执行任务也会占用内存,还可能导致请求队列阻塞,拖慢整体执行效率。
3. 未设置请求超时
client.get 未配置超时时间,若某些请求因网络问题、服务器无响应挂起,整个asyncio.gather会一直等待这些未完成的请求,导致程序无法结束。
4. 潜在的参数解析与异常缺失问题
代码中getVouchDetails函数里的params变量未定义(仅注释了##getting params from link),如果实际参数解析逻辑有错误,会导致请求失败或卡住;同时没有异常捕获,单个请求的错误可能扩散导致整体流程停滞。
修复方案
1. 替换索引查找方式
循环时同时获取索引和链接,避免O(n)的index操作:
async def poolVouch(idx, link, client): print(idx) soup = await getVouchDetails(link, client) # 数据提取逻辑 finalList.append([...]) # 在main中修改循环: for idx, link in enumerate(links): tasks.append(asyncio.create_task(poolVouch(idx, link, client)))
2. 分批执行任务
不要一次性创建100k任务,分批次执行,控制同时运行的任务数量:
async def main(links): async with httpx.AsyncClient(limits=limits) as client: batch_size = 50 # 根据服务器承受能力调整 for i in range(0, len(links), batch_size): batch = links[i:i+batch_size] tasks = [asyncio.create_task(poolVouch(idx, link, client)) for idx, link in enumerate(batch, start=i)] await asyncio.gather(*tasks)
3. 添加请求超时
为httpx请求设置合理的超时时间,避免请求无限挂起:
response = await client.get( 'https://egramswaraj.gov.in/paymentVoucherDetail.do', params=params, headers=headers, timeout=httpx.Timeout(10.0) # 10秒超时,可根据情况调整 )
4. 完善参数解析与异常处理
确保params正确从link中解析,同时添加异常捕获,避免单个请求失败导致整个程序卡住:
async def getVouchDetails(link, client): try: # 补充解析link得到params的逻辑,例如: # params = extract_params_from_link(link) response = await client.get( 'https://egramswaraj.gov.in/paymentVoucherDetail.do', params=params, headers=headers, timeout=httpx.Timeout(10.0) ) response.raise_for_status() # 抛出HTTP状态码异常 soup = BeautifulSoup(response.content, 'lxml') return soup except Exception as e: print(f"请求失败: {link}, 错误: {str(e)}") return None async def poolVouch(idx, link, client): print(idx) soup = await getVouchDetails(link, client) if soup: # 仅在获取到有效soup时提取数据 finalList.append([...])
5. 替换asyncio.ensure_future为asyncio.create_task
asyncio.create_task是Python 3.7+推荐的创建任务方式,语义更清晰。
内容的提问来源于stack exchange,提问作者Coding Dog
相关产品推荐
相关产品推荐

