繁体   English   中英

限制从Python脚本一次运行的进程数

[英]Limiting the number of processes running at a time from a Python script

我正在运行一个备份脚本,启动子进程以通过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完成?

多处理池

你有没有想过使用多处理.Pool的? 这些允许您定义用于执行所需作业的固定数量的工作进程。 这里的关键字是固定数字 ,它可以让您完全控制将要启动的rsync实例数。

查看我链接的文档中提供的示例,首先声明一个包含n进程的Pool ,然后您可以决定是将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进程。

运行rsync

您的流程生成代码将变为类似于:

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()

让我们首先澄清一些误解

我假设rsync分裂了,不再是python的一个孩子,它允许我的子进程死掉所以我不能再算了。

rsync确实“分裂”了。 在UNIX系统上,这称为fork

当进程分叉时,会创建子进程 - 所以rsync python的子进程 这个子节点独立于父节点执行 - 并且同时执行(“同时”执行)。

一个过程可以管理自己的孩子。 有特定的系统调用 ,但在谈论python时有点偏离主题,它有自己的高级接口

如果你检查subprocess.Popen的文档 ,你会发现它根本不是函数调用:它是一个类。 通过调用它,您将创建该类的实例--Popen对象 这些对象有多种方法。 特别是, wait将允许您阻止父进程(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 ,它将当前进程替换为另一个进程

这不是多线程,而是多处理。 我假设您使用的是Unix系统,如果您使用的是rsync尽管我相信它可以在Windows系统上运行。 为了控制衍生的子进程的死亡,您必须fork它们。

这里用Python做一个很好的问题。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM