含并行处理的Python代码打包exe后陷入无限自调用循环问题
解决PyInstaller打包joblib并行代码的无限递归问题
问题原因
使用pyinstaller --onefile打包含joblib Parallel的代码时,单文件exe运行会临时解压到系统临时目录。joblib启动子进程时,会误将当前exe文件当作Python解释器调用,导致程序反复启动自身,陷入无限循环。
解决方案
方法1:修改代码指定Python解释器路径
在初始化Parallel时,通过loky后端的参数指定正确的Python解释器路径,同时判断是否处于打包后的环境:
# example.py from math import sqrt from joblib import Parallel, delayed import sys import os def producer(): for i in range(6): print('Produced %s' % i) yield i def main(): is_frozen = getattr(sys, 'frozen', False) python_executable = sys.executable if is_frozen and hasattr(sys, '_MEIPASS'): # 打包后从临时解压目录获取Python解释器 python_executable = os.path.join(sys._MEIPASS, 'python.exe') out = Parallel( n_jobs=2, verbose=100, pre_dispatch='1.5*n_jobs', backend='loky', loky_kwargs={'executable': python_executable} )(delayed(sqrt)(i) for i in producer()) if __name__ == '__main__': main()
打包命令:
pyinstaller --onefile --collect-submodules joblib example.py
方法2:切换到multiprocessing后端并配置启动方式
改用multiprocessing作为joblib的后端,并在冻结环境下设置进程启动方式:
# example.py from math import sqrt from joblib import Parallel, delayed import sys import multiprocessing def producer(): for i in range(6): print('Produced %s' % i) yield i def main(): if getattr(sys, 'frozen', False): multiprocessing.set_start_method('spawn') out = Parallel( n_jobs=2, verbose=100, pre_dispatch='1.5*n_jobs', backend='multiprocessing' )(delayed(sqrt)(i) for i in producer()) if __name__ == '__main__': main()
打包命令:
pyinstaller --onefile example.py
验证
运行打包后的exe文件,若正常打印Produced x系列日志并完成计算,说明问题已解决,程序不再陷入无限循环。
内容的提问来源于stack exchange,提问作者Dimension Entangled
相关产品推荐
相关产品推荐

