我正在运行一个备份脚本,该脚本启动子进程以通过rsync执行备份。但是我无法限制它一次启动的rsyncs的数量。
这是我目前正在处理的代码:
print "active_children: ", multiprocessing.active_children()
print "active_children len: ", len(multiprocessing.active_children())
while len(multiprocessing.active_children()) > 49:
sleep(2)
p = multiprocessing.Process(target=do_backup, args=(shash["NAME"],ip,shash["buTYPE"], ))
jobs.append(p)
p.start()
当我运行数百个rsyncs时,这显示最多一个孩子。这是实际启动rsync的代码(来自do_backup函数内部),command
是包含rsync行的变量:
print command
subprocess.Popen(command, stdout=subprocess.PIPE, shell=True)
return 1
如果我向do_backup函数添加sleep(x),它将在睡眠时显示为活动子项。此外,进程表显示rsync进程的PPID为1.我从这里假设rsync分离并且不再是python的子进程,它允许我的子进程死掉所以我不能再计算它了。有没有人知道如何保持python子活着并被计算直到rsync完成?
答案 0 :(得分:6)
您是否考虑过使用multiprocessing.Pool?这些允许您定义用于执行所需作业的固定数量的工作进程。这里的关键是固定号码,它可以让你完全控制你将启动的rsync实例数。
查看我链接的文档中提供的示例,首先声明Pool
个n
个进程,然后您可以决定是map()
还是apply()
(与他们各自的_async()
兄弟姐妹一起)你的工作到了游泳池。
from multiprocessing import Pool
def f(x):
return x*x
if __name__ == '__main__':
pool = Pool(processes=4) # start 4 worker processes
pool.apply_async(f, (10,)) # evaluate "f(10)" asynchronously
...
pool.map(f, range(10))
这里显而易见的优点是,您永远不会意外地对您的机器进行分叉炸弹,因为您只会生成所请求的n
进程。
您的流程生成代码将变为类似:
from multiprocessing import Pool
def do_backup(arg1, arg2, arg3, ...):
# Do stuff
if __name__ == '__main__':
# Start a Pool with 4 processes
pool = Pool(processes=4)
jobs = []
for ... :
# Run the function
proc = pool.apply_async(func=do_backup, args=(shash["NAME"],ip,shash["buTYPE"], ))
jobs.append(proc)
# Wait for jobs to complete before exiting
while(not all([p.ready() for p in jobs])):
time.sleep(5)
# Safely terminate the pool
pool.close()
pool.join()
答案 1 :(得分:2)
让我们首先澄清一些误解
我假设rsync已经分离并且不再是一个 python的孩子,它允许我的孩子进程死亡所以我无法计算 它了。
rsync
确实“分崩离析”。在UNIX系统上,这称为fork。
当一个进程分叉时,会创建一个子进程 - 所以rsync
是是python的一个子进程。这个孩子独立于父母而且同时(“同时”)执行。
进程可以管理自己的子进程。有特定的syscalls,但在讨论python时有点偏离主题,它有自己的高级接口
如果你检查subprocess.Popen
's documentation,你会注意到它根本不是函数调用:它是一个类。通过调用它,您将创建该类的实例 - Popen object。
这些对象有多种方法。特别是,wait
将允许您block您的父进程(python),直到子进程终止。
考虑到这一点,让我们看看你的代码并简化一下:
p = multiprocessing.Process(target=do_backup, ...)
在这里,您实际上是在分叉和创建子进程。 此过程是另一个python解释器(与所有multiprocessing
进程一样),并将执行do_backup
函数。
def do_backup()
subprocess.Popen("rsync ...", ...)
在这里,您再次分支 。您将创建另一个进程(rsync
),让它在“后台”运行,因为您不是wait
。
有了这一切,我希望您能看到现有代码的前进方向。如果你想减少它的复杂性,我建议你检查并调整JoErNanO的答案,重用multiprocessing.Pool
来自动跟踪进程。
无论您决定采用哪种方式,都应该避免使用Popen
来创建rsync
进程 - 因为这会不必要地创建另一个进程。相反,请检查os.execv
,替换当前流程与另一个
答案 2 :(得分:0)
这不是多线程,而是多处理。我假设您使用的是Unix系统,如果您使用rsync
,我相信它可以在Windows系统上运行。为了控制衍生的子进程的死亡,您必须fork
。
在Python here中进行此操作有一个很好的问题。