我有三个脚本,scheduler.py
是基于multiprocessing.Process
和multiprocessing.Pipe
的并行任务运行器,第二个脚本是simulation.pyx
,这是一个包含我想通过scheduler.py
并行执行的一些类和函数的脚本,最后是一个小主脚本,我从scheduler.py
创建并行化类的实例,将其传递给simulation.pyx
中的类并运行整个事情。
当目标并行函数在simulation.pyx
中处于顶层时,一切都很好,但是一旦我尝试使用scheduler.py
与simulation.pyx
中的类函数,我就会得到一个酸洗错误。
由于代码有几千行,我只给出一些概念性的代码:
small_main_script.py
:
import simulation
import scheduler
if __name__ == '__main__':
main = simulation.Main()
scheduler = scheduler.parallel()
main.simulate(scheduler)
simulation.pyx
:
import scheduler
cdef do_something_with_job(job):
...
cdef class Main:
cdef public ...
...
def __init__(self):
...
def some_function(self,job):
...
do_something_with_job(job)
...
def simulate(self, scheduler):
for job in job_list:
scheduler.add_jobs(job)
scheduler.target_function = self.some_function
scheduler.run_in_parallel()
问题是,如果我使用无用的哑函数,比如
def sleep(job):
time.sleep(2)
并把它放在顶层,即在类之外,并行化工作得很好,但一旦我把它放在类Main
里面,我就会得到一个pickle错误。如果我使用真正的目标函数,也在类Main
中定义,我也会得到同样的错误,我不想将其移动到顶层。以下是当我在类Main
中使用虚拟函数sleep(self,job)
时发生的情况。当它在类之外时,它工作得很好。
PicklingError: Can't pickle <built-in method sleep of simulation.Main
object at 0x0D4A3C00>: it's not found as __main__.sleep
In [2]: Traceback (most recent call last):
File "<string>", line 1, in <module>
File "C:Python27libmultiprocessingforking.py", line 381, in main self = load(from_parent)
File "C:Python27libpickle.py", line 1384, in load return Unpickler(file).load()
File "C:Python27libpickle.py", line 864, in load dispatch[key](self)
File "C:Python27libpickle.py", line 886, in load_eof
raise EOFError
EOFError
我使用Python 2.7
<标题> 更新我已经设法进一步隔离了这个问题。当使用第三方包pathos multiprocessing
时,我能够pickle类函数。现在的问题似乎是,当使用函数参数是类实例时,我得到一个错误。
来自Python多处理编程指南:
Picklability:确保代理方法的参数是可picklable的。
只有顶级函数是可pickle的。
很难pickle非顶级函数(类/实例方法,嵌套函数等)的原因是因为很难在子进程中以可移植的方式查找它们。你发送实例方法去执行的进程可能不知道拥有该方法本身的对象。如编程指南所建议的:
然而,通常应该避免使用管道或队列将共享对象发送给其他进程。相反,您应该安排程序,以便需要访问其他地方创建的共享资源的进程可以从祖先进程继承该资源。
换句话说,创建一个将方法传递给目标关键字的进程。
Pathos库扩展了pickle协议,允许序列化比标准协议支持的更多类型。
通常不建议将OOP和多处理混合使用,因为存在一些可能会产生误导的极端情况。