我试图在进程之间共享一个锁。我理解共享锁的方法是将它作为参数传递给目标函数。然而,我发现甚至下面的方法也是有效的。我无法理解进程共享此锁的方式。有人能解释一下吗?
import multiprocessing as mp
import time
class SampleClass:
def __init__(self):
self.lock = mp.Lock()
self.jobs = []
self.total_jobs = 10
def test_run(self):
for i in range(self.total_jobs):
p = mp.Process(target=self.run_job, args=(i,))
p.start()
self.jobs.append(p)
for p in self.jobs:
p.join()
def run_job(self, i):
with self.lock:
print('Sleeping in process {}'.format(i))
time.sleep(5)
if __name__ == '__main__':
t = SampleClass()
t.test_run()发布于 2017-07-11 17:45:33
在Windows上(您已经说过正在使用),这类事情总是简化为关于multiprocessing如何使用pickle的详细信息,因为在Windows上跨越进程边界的所有Python数据都是通过发送端的酸洗来实现的(而在接收端则不进行筛选)。
我最好的建议是避免做引起这样的问题的事情;-)例如,在Python2下在Windows上显示的代码会爆炸,如果使用multiprocessing.Pool方法而不是multiprocessing.Process,也会在Python3下崩溃。
这不仅仅是锁,只是尝试在Python2中挑选绑定的方法(如self.run_job),想想看。您正在跨越流程边界,接收端没有对应于self的对象。self.run_job应该绑定在接收端上的对象是什么?
在Python3中,self.run_job也会对self对象的一个副本进行酸洗。这就是答案:与self相对应的self对象是在接收端通过魔术创建的。像泥一样干净。t的整个州都泡汤了,包括t.lock。这就是为什么它“起作用”。
有关更多实现细节,请参见此:
为什么我可以将实例方法传递给multiprocessing.Process,而不能传递multiprocessing.Pool?
从长远来看,如果您坚持那些显然是要工作的东西,那么您将遭受最少的神秘: pass模块--全局可调用对象(既不是实例方法,也不是本地函数),以及显式传递multiprocessing数据对象(无论是Lock、Queue、manager.list等的实例)。
发布于 2017-07-11 16:28:54
在Unix操作系统上,通过fork原语创建新进程。
fork原语的工作方式是克隆父进程内存地址空间,将其分配给子进程。子对象将拥有父内存的副本以及文件描述符和共享对象的副本。
这意味着,当您调用叉时,如果父文件已打开,子文件也将被打开。同样适用于共享对象,如管道、套接字等.
在Unix+CPython中,Locks是通过sem_open原语实现的,而sem_open原语在分叉进程时被设计为共享。
我通常建议不要将并发(特别是多进程)和面向对象( OOP )混合在一起,因为它经常导致这种误解。
编辑:
刚才看到你在使用Windows。蒂姆·彼得斯给出了正确的答案。为了抽象起见,Python试图通过它的API提供与操作系统无关的行为。当调用实例方法时,它将对对象进行筛选,并通过管道发送它。从而提供了类似于Unix的行为。
我建议您阅读方案编制准则进行多处理。你的问题特别是在第一点:
避免共享状态 应尽可能避免在进程之间转移大量数据。 最好还是坚持使用队列或管道在进程之间进行通信,而不是使用低级的同步原语。
https://stackoverflow.com/questions/45023569
复制相似问题