Cython编译项目为.pyd文件后multiprocessing模块无法正常工作的解决方案求助
Cython编译项目为.pyd文件后multiprocessing模块无法正常工作的解决方案求助
最近几个小时我一直在啃一个棘手的问题:把项目用Cython编译成纯.pyd文件后,multiprocessing模块彻底没法正常工作了。我选择这种方式的原因很明确——远程机器上绝对不能出现源码;之前试过PyInstaller,但它实在太不稳定了,编译时总是缺失多个依赖包的.dll文件,就算好不容易调稳定了,只要新增或者更新一个包的版本,整个程序就可能崩掉,所以实在不想再用它。
编译生成.pyd文件后,我写了一个main.py文件,从编译好的main.pyd里导入启动函数,以此来启动整个工作流程。我的项目规模不算小,大概有40-50个文件。
下面是我用来生成.pyd文件的setup.py代码:
from distutils.core import setup from Cython.Build import cythonize import os # Recursively collect all Python files in the folder def collect_files(base_dir): extensions = [] for root, dirs, files in os.walk(base_dir): if "brainstorming" in dirs: dirs.remove("brainstorming") if "venv" in dirs: dirs.remove("venv") for file in files: if file.endswith(".py"): # Include all Python files full_path = os.path.join(root, file) module_path = os.path.splitext(full_path.replace(base_dir + os.sep, "").replace(os.sep, "."))[0] extensions.append(full_path) return list(set(extensions)) # Ensure unique paths base_dir = "." extensions = collect_files(base_dir) setup( name="myproj", ext_modules=cythonize( extensions, compiler_directives={ "language_level": "3"} ), zip_safe=True, )
问题出在这段启动子进程的代码上:
Process(target=output_process, daemon=True, args=(<arg 1>, <arg2> ...)).start()
看起来Python的multiprocessing模块在尝试pickle这个cyfunction的时候,会动态导入该函数所在的模块,但每次都以失败告终。
output_process函数位于和调用它的文件同级的lib文件夹下,具体是lib/outputprocess.py文件,项目目录结构如下:
Project/ |-- module/ | |-- lib/ | | |-- __init__.py | | |-- outputprocess.py | |-- __init__.py | |-- module_that_calls_multiprocessing.py
不管我怎么调整,只要运行到启动子进程这一步,就会抛出这个异常:
Traceback (most recent call last): File "<string>", line 1, in <module> File "C:\Users\spaceflux\anaconda3\Lib\multiprocessing\spawn.py", line 122, in spawn_main exitcode = _main(fd, parent_sentinel) ^^^^^^^^^^^^^^^^^^^^^^^^^^ File "C:\Users\spaceflux\anaconda3\Lib\multiprocessing\spawn.py", line 132, in _main self = reduction.pickle.load(from_parent) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ModuleNotFoundError: No module named 'outputprocess'
用普通.py文件运行项目的时候一切正常,模块肯定是存在的。
我还试过把output_process函数移到调用它的同一个文件里测试,结果又出现了另一个错误:
File "C:\Users\spaceflux\anaconda3\Lib\multiprocessing\process.py", line 121, in start self._popen = self._Popen(self) ^^^^^^^^^^^^^^^^^ File "C:\Users\spaceflux\anaconda3\Lib\multiprocessing\context.py", line 224, in _Popen return _default_context.get_context().Process._Popen(process_obj) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "C:\Users\spaceflux\anaconda3\Lib\multiprocessing\context.py", line 336, in _Popen return Popen(process_obj) ^^^^^^^^^^^^^^^^^^ File "C:\Users\spaceflux\anaconda3\Lib\multiprocessing\popen_spawn_win32.py", line 94, in __init__ reduction.dump(process_obj, to_child) File "C:\Users\spaceflux\anaconda3\Lib\multiprocessing\reduction.py", line 60, in dump ForkingPickler(file, protocol).dump(obj) _pickle.PicklingError: Can't pickle <cyfunction output_process at 0x0000023151445970>: import of module '<my module>' failed
有没有大佬能给点解决思路?我真的挺喜欢.pyd这种方式的,编译速度快,在生产环境里调试和打热补丁也方便,但如果有其他可行的方案我也愿意尝试!
备注:内容来源于stack exchange,提问作者Martin Todorov
相关产品推荐
相关产品推荐

