(Python 3.4,Linux)。
我有一个主流程' P',它分叉8个流程(' C1'到' C8')。我想创建multiprocessing.Barrier
,以确保所有8个子进程在某一点同步。
如果我在父进程中定义同步原语,那么一切正常,所以当我分叉子进程时,它被正确地继承:
import multiprocessing as mp
barrier = mp.Barrier(8)
def f():
# do something
barrier.wait()
# do more stuff
def main():
for i in range(8):
p = mp.Process(target = f)
p.start()
if __name__ == '__main__':
main()
但在我的情况下,我不知道创建Barrier
对象所需的详细信息,直到子进程开始之后(我不知道我要传递的参数为action
参数)。因此,我想在其中一个子进程中创建Barrier
,但我不知道如何将其提供给其他子进程。以下工作当然不会起作用,因为子进程中的8个Barrier
对象完全相互独立:
import multiprocessing as mp
def f():
global barrier
# do something
barrier = mp.Barrier(8)
barrier.wait()
# do more stuff
def main():
for i in range(8):
p = mp.Process(target = f)
p.start()
if __name__ == '__main__':
main()
我正在考虑在其中一个子流程中创建barrier
,然后使用multiprocessing.Queue
将其传递给其他子流程(或者如果Queue
不接受Barrier
对象,使用multiprocessing.Manager().Barrier
)。但是,即使这样可行,我也不知道如何确保只有一个进程实际put
个(7个副本)同步原语进入队列,而其他进程只有get
个。 (当然,我可以在父进程中创建另一个同步原语只是为了做到这一点,但我不得不重构我的代码,以便在父进程中创建原始的Barrier
。)
答案 0 :(得分:1)
以下是一个示例,说明如何通过在一个孩子中创建multiprocessing.managers.BaseManager
,然后从所有其他孩子连接到该经理来实现此目的。请注意,它需要将multiprocessing.Lock
从父级传递给所有子级以用于同步目的,您提到的是您希望避免这种情况。不过,我不确定是否有其他选择。
import multiprocessing as mp
from multiprocessing.managers import BaseManager
class MyManager(BaseManager):
pass
def f(lock):
# do something
with lock:
try:
MyManager.register('get_barrier')
m = MyManager(address=('localhost', 5555), authkey=b'akey')
m.connect()
b = m.get_barrier()
print("Got the barrier from the manager")
except OSError as e:
# We are the first. Create the manager, register
# a mp.Barrier instance with it, and start it up.
print("Creating the manager...")
b = mp.Barrier(8)
MyManager.register('get_barrier', callable=lambda:b)
m = MyManager(address=('localhost', 5555), authkey=b'akey')
m.start()
b.wait()
print("Done!")
# do more stuff
def main():
lock = mp.Lock()
for i in range(8):
p = mp.Process(target=f, args=(lock,))
p.start()
if __name__ == '__main__':
main()
输出:
Creating the manager...
Got the barrier from the manager
Got the barrier from the manager
Got the barrier from the manager
Got the barrier from the manager
Got the barrier from the manager
Got the barrier from the manager
Got the barrier from the manager
Done!
Done!
Done!
Done!
Done!
Done!
Done!
Done!
答案 1 :(得分:1)
是否可以简单地捕获流程的ID并仅在其中一个中手动调用您的操作?像这样的东西?
import multiprocessing as mp
barrier = mp.Barrier(8)
def f():
# create action
def action():
print("action was run on process {}.".format(id))
# do something
print("Hello from process {}.".format(id))
id = barrier.wait()
if id == 0:
action()
barrier.wait()
# Do more stuff
def main():
for i in range(8):
p = mp.Process(target = f)
p.start()
if __name__ == '__main__':
main()
答案 2 :(得分:0)
这是一个也可以在Windows上使用的版本(缺少的fork
会引起其他问题):
import multiprocessing as mp
def procs(uid_barrier):
uid, barrier = uid_barrier
print(uid, 'waiting')
barrier.wait()
print(uid, 'past barrier')
def main():
N_PROCS = 10
with mp.Manager() as man:
barrier = man.Barrier(N_PROCS)
with mp.Pool(N_PROCS) as p:
p.map(procs, ((uid, barrier) for uid in range(N_PROCS)))
if __name__ == '__main__':
mp.freeze_support()
main()