Python循环随迭代次数增加变慢,仅执行图片加载关闭操作
问题分析与优化方案
代码复现
from PIL import Image from tqdm import tqdm for idx, img in enumerate(tqdm(all_images)): image = Image.open(img) image.close()
性能下降原因
- 内存泄漏触发swap:尽管手动调用了
image.close(),但PIL的Image对象底层关联的内存资源可能未被Python垃圾回收器及时回收。随着循环推进,内存占用持续攀升,当物理内存耗尽时系统会启用磁盘交换分区(swap),而磁盘IO速度远低于内存,直接导致迭代速度骤降。 - 文件句柄残留:部分场景下
image.close()无法完全释放底层文件句柄,累积的句柄会增加系统资源开销,拖慢后续文件操作效率。 - 磁盘缓存耗尽:初始阶段系统将高频访问的图像文件缓存到内存,迭代500次后缓存空间不足,后续图像需从磁盘直接读取,速度大幅降低(机械硬盘场景下尤为明显)。
优化方案
1. 用上下文管理器自动释放资源
改用with语句,它会在代码块结束后自动调用close(),且能处理异常场景下的资源释放,比手动调用更可靠:
from PIL import Image from tqdm import tqdm for idx, img in enumerate(tqdm(all_images)): with Image.open(img) as image: # 执行图像处理逻辑 pass
2. 主动触发垃圾回收
在每次循环后手动调用垃圾回收,及时清理未被回收的内存资源:
import gc from PIL import Image from tqdm import tqdm for idx, img in enumerate(tqdm(all_images)): image = Image.open(img) image.close() gc.collect()
3. 优化文件路径加载方式
如果all_images是加载了所有文件路径的大列表,改用生成器(如glob.iglob代替glob.glob),减少内存占用:
from PIL import Image from tqdm import tqdm import glob # 用生成器分批获取文件路径,而非一次性加载全部 all_images = glob.iglob("/path/to/images/*.jpg") for idx, img in enumerate(tqdm(all_images)): with Image.open(img) as image: pass
4. 优化存储与缓存
- 将图像文件迁移至SSD,提升磁盘读取速度;
- 若文件数量极大,可分批将图像加载到内存缓存区,减少磁盘IO次数。
内容的提问来源于stack exchange,提问作者AnarKi
相关产品推荐
相关产品推荐

