Pillow+multiprocessing批量处理图片通道时程序卡住无报错
问题说明
使用pillow和multiprocessing批量处理图片时,程序无报错但长时间挂起无法结束:
- 需求:遍历目录下数百张JPEG图片,拆分RGB通道后用
ImageChops.add合并绿色通道、蓝色通道,结果保存为新文件 - 运行环境:macOS 10.16 x86_64
- 初始代码如下:
import platform from PIL import Image from PIL import ImageChops import glob from multiprocessing import Pool print(platform.platform()) # macOS-10.16-x86_64-i386-64bit def get_processed_im(f): im = Image.open(f) im_r, im_g, im_b = im.split() im_rf = ImageChops.add(im_g, im_b) # save images im_rf.save("RF_"+f, "JPEG") if __name__ == '__main__': # Create a pool of processes to check files p = Pool() # Create a list of files to process files = [f for f in glob.glob("*.jpeg")] print(f'Files to process: {len(files)}') print(files) p.map(get_processed_im, files)
- 运行输出:
Files to process: 4 ['im1.jpeg', 'im2.jpeg', 'im3.jpeg', 'im4.jpeg']
输出以上内容后程序无报错,但长时间运行无法结束。
问题原因
挂起由两个因素共同导致:
- macOS平台下Python 3.8+版本的
multiprocessing默认使用spawn模式启动子进程,该模式下Pillow的C扩展初始化逻辑存在死锁风险,子进程启动后会卡在资源初始化步骤无法执行实际任务 - 代码未显式回收进程池资源,且打开的图片对象未手动释放,文件句柄泄漏会进一步加剧进程挂起概率
修复方案
按以下步骤调整代码即可正常运行:
- 显式设置多进程启动模式为
fork,避开spawn模式下的C扩展死锁问题 - 用上下文管理器打开图片,处理完成后自动释放文件句柄
- 进程池使用完成后显式调用
close()和join(),确保所有子进程任务执行完成后资源正常回收 - 增加文件过滤逻辑,排除之前运行生成的
RF_开头的结果文件,避免重复处理
修复后的完整可运行代码:
import platform from PIL import Image from PIL import ImageChops import glob from multiprocessing import Pool, set_start_method def get_processed_im(f): with Image.open(f) as im: _, im_g, im_b = im.split() im_rf = ImageChops.add(im_g, im_b) im_rf.save(f"RF_{f}", "JPEG") print(f"Finish processing: {f}") if __name__ == '__main__': set_start_method('fork', force=True) print(platform.platform()) # 可根据CPU核心数调整进程数,建议设为物理核心数 p = Pool(processes=4) # 过滤已生成的结果文件 files = [f for f in glob.glob("*.jpeg") if not f.startswith("RF_")] print(f'Files to process: {len(files)}') print(files) p.map(get_processed_im, files) p.close() p.join() print("All tasks completed.")
额外说明
如果调整后仍有异常,可以先把多进程逻辑注释掉,用普通for循环串行处理文件,确认Pillow的图片处理逻辑本身没有问题后,再开启多进程加速。
内容的提问来源于stack exchange,提问作者olveraa
相关产品推荐
相关产品推荐

