我试图理解使用python mutiprocessing
观察到的以下奇怪行为。
示例testClass: 进口口 导入多处理
class testClass(multiprocessing.Process):
def __del__(self):
print "__del__ PID: %d" % os.getpid()
print self.a
def __init__(self):
multiprocessing.Process.__init__(self)
print "__init__ PID: %d" % os.getpid()
self.a = 0
def run(self):
print "method1 PID: %d" % os.getpid()
self.a = 1
还有一个小测试程序: 来自testClass import testClass
print "Start"
proc_list = []
proc_list.append(testClass())
proc_list[-1].start()
proc_list[-1].join()
print "End"
这会产生:
Start
__init__ PID: 89578
method1 PID: 89585
End
__del__ PID: 89578
0
为什么不打印1
?
我猜测它与run
实际上正在不同进程上执行的事实有关,这是可以看到的。如果这是预期的行为,那么每个人如何使用多处理过程中的流程与需要打开数据库的流程一样昂贵__init__
?
在多处理文档中,不应该更好地突出显示这种行为吗?
答案 0 :(得分:0)
您可以将昂贵的初始化包装在上下文管理器中:
def run(self):
with expensive_initialization() as initialized_object:
do_some_logic_here(initialized_object)
在调用do_some_logic_here
之前,您将有机会正确初始化对象,并在离开上下文管理器块之后正确释放资源。
请参阅documentation。
答案 1 :(得分:0)
当调用start()
时,解释器会分叉并创建一个子进程,该进程从父进程获取页表的副本。这些指向标记为只读且仅在写入时复制的页面(COW)。解释器在子进程中执行run
时,会访问代表PyObject
的{{1}}的子副本。未触及父母的记忆。子节点还获取文件描述符表的副本,这意味着如果父节点打开了连接,则该子文件将继承该文件描述符。您可以看到(a
)孩子是通过strace
创建的,而不是clone
:
CLONE_FILES
因此,从克隆手册页:
如果未设置CLONE_FILES,子进程将继承clone()时在调用进程中打开的所有文件描述符的副本。 (子节点中的重复文件描述符引用相同的打开文件描述(请参阅open(2))作为调用进程中的相应文件描述符。)打开或关闭文件描述符或更改文件描述符标志的后续操作,由调用进程或子进程不会影响其他进程。