批量API请求结果通过Pandas追加CSV时内存过载的优化方案咨询
解决批量API请求后内存持续增长的问题
这个内存持续上升的问题我之前处理过,核心是你当前的代码每批会一次性持有10k条请求的全部结果,这些大对象的内存没法被及时回收,导致内存占用不断累积。咱们来拆解问题并给出优化方案:
问题根源分析
- 一次性持有全量结果:
asyncio.gather(*tasks)会把10k个请求的结果全部存在my_data列表里,接着又转成10k行的DataFrame——这两个对象会占用大量内存,而且处理完一批后,Python的垃圾回收机制可能不会立刻释放这些内存(比如存在隐式引用,或者GC触发时机滞后)。 - 无主动内存释放操作:处理完一批后,没有显式清理这些大对象,导致它们一直占用内存直到下一次GC触发,33批下来内存就会持续攀升。
优化方案
方案1:拆分更小的子批次(平衡效率与内存)
把10k的大批次拆成更小的子批次(比如每100个一组),处理完一个子批次就写入CSV并释放内存,避免一次性持有过多数据:
async def loop_handler(my_list, session, csvfile): # 定义子批次大小,可根据内存情况调整 sub_batch_size = 100 # 判断是否需要写入表头(仅文件为空时写一次) write_header = csvfile.tell() == 0 for i in range(0, len(my_list), sub_batch_size): sub_batch = my_list[i:i+sub_batch_size] # 为子批次创建任务 tasks = [asyncio.ensure_future(get_single_req(session, link)) for link in sub_batch] sub_data = await asyncio.gather(*tasks) # 写入子批次数据 df = pd.DataFrame(sub_data) df.to_csv(csvfile, index=False, header=write_header, mode='a') # 第一次写入后就不再写表头 write_header = False # 显式删除大对象,帮助垃圾回收 del sub_data, df # 给事件循环一点时间处理GC await asyncio.sleep(0)
方案2:逐请求写入(内存占用最低)
如果对效率要求不是极端高,可以直接在获取单个请求结果后就写入CSV,完全避免大列表和大DataFrame的内存占用:
async def loop_handler(my_list, session, csvfile): write_header = csvfile.tell() == 0 for link in my_list: # 获取单个请求结果 result = await get_single_req(session, link) # 写入单条数据 df = pd.DataFrame([result]) df.to_csv(csvfile, index=False, header=write_header, mode='a') write_header = False # 及时清理对象 del df, result await asyncio.sleep(0)
额外优化建议
- 检查
get_single_req函数:确保函数内部没有持有大对象(比如未关闭的响应体、多余的缓存),避免每个请求都留下内存垃圾。 - 手动触发GC(可选):如果内存还是有累积,可以在每批处理完后手动调用垃圾回收:
不过优先通过代码优化减少内存占用,手动GC作为兜底手段。import gc gc.collect()
效果说明
优化后,每批处理时只会持有子批次或单条数据的内存,处理完就释放,内存占用会保持在一个稳定的低水平,不会再持续增长。
内容的提问来源于stack exchange,提问作者L M
相关产品推荐
相关产品推荐

