概述使用cykthon编译带有dask或joblib多处理的可执行文件导致错误
我正在转换一些串行处理的python作业与dask或joblib多处理。 可悲的是我需要在windows上工作。
当从IPython或从命令行运行python文件与python一切运行良好。
当用cython编译一个可执行文件时,它不再运行正常:一步一步越来越多的进程(无限制和大于请求进程的数量)得到startet并阻止我的系统。
它不知何故感觉像多处理炸d – 但当然, if __name__==\”__main__:\”具有控制块 – 通过从命令行python调用罚款批准。
我的cython调用是cython –embed –verbose –annotate THECODE.PY ,我用gcc -time -municode -DMS_WIN64 -mthreads -Wall -O -I\”PATH_TO_include\” -L\”PATH_TO_libs\” THECODE.c -lpython36 -o THECODE编译gcc -time -municode -DMS_WIN64 -mthreads -Wall -O -I\”PATH_TO_include\” -L\”PATH_TO_libs\” THECODE.c -lpython36 -o THECODE导致一个windows可执行文件THECODE.exe 。
与其他(单一处理)运行良好的代码。
这个问题对于dask和joblib来说似乎是一样的(这可能意味着,dask可以像joblib一样工作)。
有什么build议么?
对于那些对mcve感兴趣的人 :只要从Multiprocessing Bomb获得第一个代码,然后使用上面的cython命令编译代码,就会导致一个可执行文件冒用你的系统。 (我刚刚试过:-))
我只是通过在代码示例中添加一行来显示__name__ :
import multiprocessing def worker(): \”\”\”worker function\”\”\” print(\’Worker\’) return print(\”–>\” + __name__ + \”<–\”) if __name__ == \’__main__\’: jobs = [] for i in range(5): p = multiprocessing.Process(target=worker) jobs.append(p) p.start()
用python运行这段代码的时候会显示出来
15秒的空闲延迟加载windows本机python模块
在windows上,Ctrl-C退出Cython解释器
在windows上的Cython记忆体
将预编译的Cython代码分发到windows
我如何编译windows的cymunk?
__main__ __mp_main__ __mp_main__ __mp_main__ __mp_main__ __mp_main__
(其他输出抑制)。 解释如果决定有效。 在cython和编译显示之后运行可执行文件时
__main__ __main__ __main__ __main__ __main__ __main__
而且越来越多。 因此,模块的工作人员不再像import一样masqueraded ,因此每个工人都试图以recursion方式启动五个新模块。
如何运行cython命令行选项
Cython中的Hello World程序在安装python-dev和链接库之后失败
为什么windows上的Cython扩展取决于pythonXX.dll,而不是MacOSX?
windows Python程序重启(不同生活中的罪过)
在集群上使用Python,Cython和GSL
起初,我很惊讶地发现,你的cython版本以某种方式工作,但它只是一个工作的外观。 但是,有些黑客攻击似乎有可能使其工作。
我在linux上,所以我使用mp.set_start_method(\’spawn\’)来模拟windows的行为。
在spawn -mode中会发生什么? 让我们添加一些sleep ,所以我们可以调查的过程:
#bomb.py import multiprocessing as mp import sys import time def worker(): time.sleep(50) print(\’Worker\’) return if __name__ == \’__main__\’: print(\”Starting…\”) time.sleep(20) mp.set_start_method(\’spawn\’) ## use spawn! jobs = [] for i in range(5): p = mp.Process(target=worker) jobs.append(p) p.start()
通过使用pgrep python我们可以看到,起初只有一个python进程,然后是7(!)不同的pID 。 我们可以通过cat /proc/<pID>/cmdline看到命令行参数。 新进程中有5个命令行
-c \”from multiprocessing.spawn import spawn_main; spawn_main(tracker_fd=5,pipe_handle=11)\” –multiprocessing-fork
和一个:
-c \”from multiprocessing.semaphore_tracker import main;main(4)\”
也就是说,父进程启动6个新的python解释器实例,每个新启动的解释器都通过命令行选项执行从父进程发送的代码,信息通过管道共享。 这6个python实例之一是一个跟踪器,它可以观察整个事物。
好的,如果cythonized + embeded会发生什么? 和普通的python一样,唯一不同的是,可执行文件的启动代替python。 但与python解释器不同的是,它不会执行/不知道命令行参数,所以main函数会一遍又一遍地运行。
有一个简单的解决方法:让bomb -exe启动python解释器
… if __name__ == \’__main__\’: mp.set_executable(<PATH TO PYTHON>) ….
现在这个bomb不再是一个多处理炸d!
但是,目标可能不是有一个Python解释器,所以我们需要让我们的程序知道可能的命令行:
import re …… if __name__ == \’__main__\’: if len(sys.argv)==3: # should start in semaphore_tracker mode nr=List(map(int,re.findall(r\’d+\’,sys.argv[2]))) sys.argv[1]=\’–multiprocessing-fork\’ # this canary is needed for multiprocessing module to work from multiprocessing.semaphore_tracker import main;main(nr[0]) elif len(sys.argv)>3: # should start in slave mode fd,pipe=map(int,sys.argv[2])) print(\”I\’m a slave!,fd=%d,pipe=%d\”%(fd,pipe)) sys.argv[1]=\’–multiprocessing-fork\’ # this canary is needed for multiprocessing module to work from multiprocessing.spawn import spawn_main; spawn_main(tracker_fd=fd,pipe_handle=pipe) else: #main mode print(\”Starting…\”) mp.set_start_method(\’spawn\’) jobs = [] for i in range(5): p = mp.Process(target=worker) jobs.append(p) p.start()
现在,我们的炸d不需要一个独立的python解释器,并在工人完成后停下来。 请注意以下事项:
决定哪种模式bomb应该启动的方式并不是非常安全的,但是我希望你能够获得这个要点
–multiprocessing-fork只是一个金丝雀,它不会做任何事情,只有在那里,看到这里 。
我想结束一个免责声明:我没有太多的多处理模块的经验,没有在windows上,所以我不知道这个解决方案应该建议。 但至少这是一个有趣的:)
注意:更改后的代码也可以与python一起使用,因为执行\”from multiprocessing.spawn import spawn_main; spawn_main(tracker_fd=5,pipe_handle=11)\” –multiprocessing-fork python更改了sys.argv所以代码不再看到原来的命令行和len(sys.argv)是1 。
从ead的答案(或那里给出的想法)的启发下,我找到了一个非常简单的解决方案 – 或者让我们更好地称之为解决方法。
对于我只是改变if子句
if __name__ == \’__main__\’: if len(sys.argv) == 1: main() else: sys.argv[1] = sys.argv[3] exec(sys.argv[2])
做到了。
这个工程的原因是(在我的情况下):当调用原始的.py文件时,工作者的__name__被设置为__mp_main__ (但是所有的进程只是普通的.py文件)。
当运行(cython)编译版本时,worker的name是不可用的,但是worker被调用的是不同的,因此我们可以通过argv中的那个参数来识别它们。 在我的情况下,工人的argv读取
[\’MYPROGRAMM.exe\’,\’-c\’,\’from multiprocessing.spawn import spawn_main; spawn_main(parent_pID=9316,pipe_handle =392)\’,\’–multiprocessing-fork\’]
因此,在argv[2]了用于激活worker的代码,并使用上面的命令执行。
当然,如果你需要编译文件的参数,你需要更大的努力,也许在调用中解析parent_pID。 但就我而言,这只是过分的。
我认为根据提交的错误报告的细节,我可以在这里提供最优雅的解决方案
if __name__ == \’__main__\’: if sys.argv[0][-4:] == \’.exe\’: setattr(sys,\’froZen\’,True) multiprocessing.freeze_support() YOURMAINROUTINE()
在windows上需要freeze_support() – freeze_support() – 参见python多处理文档 。
如果只在该行内运行python,那已经很好了。
但不知何故,cython显然没有意识到这些东西(文档告诉它用py2exe , PyInstaller和cx_Freeze测试)。 这可以通过setattr -call来缓解,只有在编译时才可以使用,因此通过文件扩展来决定。
总结
以上是内存溢出为你收集整理的使用cykthon编译带有dask或joblib多处理的可执行文件导致错误全部内容,希望文章能够帮你解决使用cykthon编译带有dask或joblib多处理的可执行文件导致错误所遇到的程序开发问题。
如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。
请登录后查看评论内容