Python:在生成的进程之间共享锁

Zil*_*il0 6 python multiprocessing python-multiprocessing

最终目标是在后台执行一个方法,但不是并行:当多个对象调用此方法时,每个对象都应该等待轮到它们继续执行。为了实现在后台运行,我必须在子进程(而不是线程)中运行该方法,并且我需要使用spawn(而不是fork)来启动它。为了防止并行执行,显而易见的解决方案是在进程之间共享全局锁。
当进程被分叉时(这是 Unix 上的默认设置),很容易实现,如以下两个代码中所强调的那样。
我们可以将它作为类变量共享:

import multiprocessing as mp
from time import sleep

class OneAtATime:

    l = mp.Lock()

    def f(self):
        with self.l:
            sleep(1)
        print("Hello")

if __name__ == "__main__":
    a = OneAtATime()
    b = OneAtATime()
    p1 = mp.Process(target = a.f)
    p2 = mp.Process(target = b.f)
    p1.start()
    p2.start()
Run Code Online (Sandbox Code Playgroud)

或者我们可以将它传递给方法:

import multiprocessing as mp
from time import sleep

class OneAtATime:
    def f(self, l):
        with l:
            sleep(1)
        print("Hello")

if __name__ == "__main__":
    a = OneAtATime()
    b = OneAtATime()
    m = mp.Manager()
    l = mp.Lock()
    p1 = mp.Process(target = a.f, args = (l,))
    p2 = mp.Process(target = b.f, args = (l,))
    p1.start()
    p2.start()
Run Code Online (Sandbox Code Playgroud)

这两个代码都具有以一秒的间隔打印“hello”的适当行为。然而,当将启动方法更改为“生成”时,它们就会损坏。
第一个 (1) 同时打印两个“hello”。这是因为类的内部状态没有被腌制,所以它们没有相同的锁。
第二个 (2) 在运行时失败并出现 FileNotFoundError。我认为这与锁不能被腌制的事实有关:请参阅Python在进程之间共享锁
在这个答案中,建议了两个修复(旁注:我不能使用池,因为我想随机创建任意数量的进程)。
我还没有找到适应第二个修复的方法,但我尝试实现第一个修复:

import multiprocessing as mp
from time import sleep

if __name__ == "__main__":
    mp.set_start_method('spawn')

class OneAtATime:
    def f(self, l):
        with l:
            sleep(1)
        print("Hello")

if __name__ == "__main__":
    a = OneAtATime()
    b = OneAtATime()
    m = mp.Manager()
    l = m.Lock()
    p1 = mp.Process(target = a.f, args = (l,))
    p2 = mp.Process(target = b.f, args = (l,))
    p1.start()
    p2.start()
Run Code Online (Sandbox Code Playgroud)

此操作失败,并出现 AttributeError 和 FileNotFoundError (3)。事实上,当使用 fork 方法 (4) 时,它也会失败 (BrokenPipe)。
在生成的进程之间共享锁的正确方法是什么?
对我编号的四个失败的快速解释也很好。我在 Archlinux 下运行 Python 3.6。

Zil*_*il0 3

只要脚本不会过早退出,最后一个代码片段就可以工作。加入流程就足够了:

import multiprocessing as mp
from time import sleep

class OneAtATime:
    def f(self, l):
        with l:
            sleep(1)
        print("Hello")

if __name__ == "__main__":
    mp.set_start_method('spawn')
    a = OneAtATime()
    b = OneAtATime()
    m = mp.Manager()
    l = m.Lock()
    p1 = mp.Process(target = a.f, args = (l,))
    p2 = mp.Process(target = b.f, args = (l,))
    p1.start()
    p2.start()
    p1.join()
    p2.join()
Run Code Online (Sandbox Code Playgroud)

有关它导致的错误的更多信息,请参见此处/sf/answers/1781954611/