2014-08-28 134 views
25

我正在尝试使用部分函数,​​以便pool.map()可以针对具有多个参数(在本例中为Lock()对象)的函数。Python共享进程之间的锁

下面是示例代码(从答案带到我的前面的问题):

from functools import partial 

def target(lock, iterable_item): 
    for item in items: 
     # Do cool stuff 
     if (... some condition here ...): 
      lock.acquire() 
      # Write to stdout or logfile, etc. 
      lock.release() 

def main(): 
    iterable = [1, 2, 3, 4, 5] 
    pool = multiprocessing.Pool() 
    l = multiprocessing.Lock() 
    func = partial(target, l) 
    pool.map(func, iterable) 
    pool.close() 
    pool.join() 

然而,当我运行此代码,我得到的错误:

Runtime Error: Lock objects should only be shared between processes through inheritance. 

我是什么在这里失踪?我怎样才能分享我的子流程之间的锁?

+0

还有关于同样的问题的另一个问题,虽然他们的具体错误是不同的 - [使用多处理.Pool:酸洗错误锁定问题](http://stackoverflow.com/questions/17960296/trouble-usinga-a-锁 - 多处理 - 池 - 酸洗 - 错误) – 2014-08-28 21:03:32

回答

46

对不起,我应该在回答您的其他问题时发现了这个问题。您无法将正常的multiprocessing.Lock对象传递给Pool方法,因为它们不能被酸洗。有两种方法可以解决这个问题。一种方法是建立Manager()并传递Manager.Lock()

def main(): 
    iterable = [1, 2, 3, 4, 5] 
    pool = multiprocessing.Pool() 
    m = multiprocessing.Manager() 
    l = m.Lock() 
    func = partial(target, l) 
    pool.map(func, iterable) 
    pool.close() 
    pool.join() 

这是一个有点重量级的,虽然,使用Manager需要产生另一个进程来承载Manager服务器。并且所有对acquire/release的呼叫都必须通过IPC发送到该服务器。

另一种选择是在池创建时使用initializer kwarg传递常规multiprocessing.Lock()。这会让你的锁实例中的所有童工全球:

def target(iterable_item): 
    for item in items: 
     # Do cool stuff 
     if (... some condition here ...): 
      lock.acquire() 
      # Write to stdout or logfile, etc. 
      lock.release() 
def init(l): 
    global lock 
    lock = l 

def main(): 
    iterable = [1, 2, 3, 4, 5] 
    l = multiprocessing.Lock() 
    pool = multiprocessing.Pool(initializer=init, initargs=(l,)) 
    pool.map(target, iterable) 
    pool.close() 
    pool.join() 

第二个解决方案具有不再需要partial副作用。

+0

好的,再次感谢你,先生。这看起来正是我所需要的。真的很感激继续的帮助!其他选项看起来超级参与。我将使用初始化函数来共享全局锁。 – DJMcCarthy12 2014-08-28 21:47:47

+0

这工作得很好。我还在init中加入了一个'Queue',以保存在每次调用中传递的信息。 – fantabolous 2015-08-17 15:11:43

+1

@dano非常感谢您的回答,我也有相同的查询,并且这个查询完美地解决了这个问题,但是我有另一个查询,为什么这种方法不经常用于在进程间共享状态,而不是通过Manager对象运行服务器进程和代理访问有其自己的开销? – bawejakunal 2016-02-22 17:00:47