Python : 在生成的进程之间共享一个锁
Python : sharing a lock between spawned processes
最终目标是在后台执行一个方法,但不是并行执行:当多个对象调用此方法时,每个对象都应等待轮到他们继续执行。要在后台实现 运行ning,我必须 运行 子进程(而不是线程)中的方法,并且我需要使用 spawn(而不是 fork)启动它。为了防止并行执行,显而易见的解决方案是在进程之间共享一个全局锁。
当进程被分叉时,这是 Unix 上的默认设置,很容易实现,如下面两个代码中突出显示的那样。
我们可以将其作为 class 变量共享:
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()
或者我们可以将它传递给方法:
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()
这两个代码都具有以一秒为间隔打印 "hello" 的适当行为。
但是,当将 start method 更改为 'spawn' 时,它们会损坏。
第一个 (1) 同时打印两个 "hello"。这是因为,所以他们没有相同的锁。
第二个 (2) 在 运行 时因 FileNotFoundError 失败。我认为这与锁不能被 pickle 的事实有关:见 Python sharing a lock between processes.
在这个答案中,提出了两个修复建议(旁注:我不能使用池,因为我想随机创建任意数量的进程)。
我还没有找到适应第二个修复的方法,但我尝试实现第一个:
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()
由于 AttributeError 和 FileNotFoundError (3) 而失败。事实上,当使用 fork 方法时,它也会失败 (BrokenPipe) (4).
在生成的进程之间共享锁的正确方法是什么?
对我编号的四个失败进行快速解释也很好。
我在 Archlinux 下 运行ning Python 3.6。
恭喜,您已完成 90% 的进度。最后一步其实也不难
是的,您的最终代码块因 AttributeError 而失败,但具体错误是什么? "Can't get attribute 'OneAtATime' on "。这与您已经遇到的问题非常相似 - 它不是酸洗 class OneAtATime。
我进行了以下更改,效果如您所愿:
file ooat.py:
from time import sleep
class OneAtATime:
def f(self, l):
with l:
sleep(1)
print("Hello")
interactive shell:
import multiprocessing as mp
from oaat import OneAtATime
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()
您可能会注意到,我实际上并没有做任何事情 - 只是将您的代码分成两个单独的文件。试一试,您会发现效果很好。 (至少,它对我有用,在 ubuntu 上使用 python 3.5。)
最后一个代码片段有效,前提是脚本不会过早退出。加入进程就足够了:
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()
有关它导致的错误的更多信息,请点击此处 。
最终目标是在后台执行一个方法,但不是并行执行:当多个对象调用此方法时,每个对象都应等待轮到他们继续执行。要在后台实现 运行ning,我必须 运行 子进程(而不是线程)中的方法,并且我需要使用 spawn(而不是 fork)启动它。为了防止并行执行,显而易见的解决方案是在进程之间共享一个全局锁。
当进程被分叉时,这是 Unix 上的默认设置,很容易实现,如下面两个代码中突出显示的那样。
我们可以将其作为 class 变量共享:
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()
或者我们可以将它传递给方法:
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()
这两个代码都具有以一秒为间隔打印 "hello" 的适当行为。
但是,当将 start method 更改为 'spawn' 时,它们会损坏。
第一个 (1) 同时打印两个 "hello"。这是因为
第二个 (2) 在 运行 时因 FileNotFoundError 失败。我认为这与锁不能被 pickle 的事实有关:见 Python sharing a lock between processes.
在这个答案中,提出了两个修复建议(旁注:我不能使用池,因为我想随机创建任意数量的进程)。
我还没有找到适应第二个修复的方法,但我尝试实现第一个:
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()
由于 AttributeError 和 FileNotFoundError (3) 而失败。事实上,当使用 fork 方法时,它也会失败 (BrokenPipe) (4).
在生成的进程之间共享锁的正确方法是什么?
对我编号的四个失败进行快速解释也很好。
我在 Archlinux 下 运行ning Python 3.6。
恭喜,您已完成 90% 的进度。最后一步其实也不难
是的,您的最终代码块因 AttributeError 而失败,但具体错误是什么? "Can't get attribute 'OneAtATime' on "。这与您已经遇到的问题非常相似 - 它不是酸洗 class OneAtATime。
我进行了以下更改,效果如您所愿:
file ooat.py:
from time import sleep
class OneAtATime:
def f(self, l):
with l:
sleep(1)
print("Hello")
interactive shell:
import multiprocessing as mp
from oaat import OneAtATime
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()
您可能会注意到,我实际上并没有做任何事情 - 只是将您的代码分成两个单独的文件。试一试,您会发现效果很好。 (至少,它对我有用,在 ubuntu 上使用 python 3.5。)
最后一个代码片段有效,前提是脚本不会过早退出。加入进程就足够了:
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()
有关它导致的错误的更多信息,请点击此处 。