【发布时间】:2018-09-22 23:13:04
【问题描述】:
我有一个使用subprocess.Popen() 运行和管理许多服务的应用程序。这些服务中的每一个都会运行,直到被明确告知要关闭。我注意到从subprocess.Popen() 调用返回的时间以相当线性的速度增加,因为仲裁器产生了更多的进程。
我的基本代码如下所示:
process_list = []
for command in command_list:
start_tm = time.time()
process = subprocess.Popen(cmd,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
end_tm = time.time()
print end_tm-start_tm
process_list.append(process)
我看到end_tm-start_tm 的打印量随着我产生越来越多的进程而增加。每个command 运行的服务可以是任何顺序,我看到相同的行为。时间增加不是完全线性的,但我一直看到一个模式:第一个进程需要约 0.005 秒才能产生,第 10 个需要约 0.125 秒,第 20 个需要约 0.35 秒,依此类推。
我的仲裁进程运行超过 100 个子进程。我可以将其拆分,以便多个仲裁器分别运行较少数量的子进程,但我想首先了解问题所在。一个进程拥有许多子进程的开销是否如此之大,以至于每个额外的子进程都会增加subprocess.Popen() 的返回时间?有什么办法可以缓解这种情况吗?
编辑:我将我的单个仲裁进程一分为二。在我之前的测试中,我的仲裁器运行了 64 个进程。我为我的仲裁器创建了两个独立的配置,每个配置运行 32 个进程。我运行第一个仲裁器,让它完全启动所有 32 个进程,然后启动第二个仲裁器。
在这两种情况下,第一个进程再次启动大约需要 0.005 秒,而第 32 个也是最后一个进程大约需要大约 0.45 秒才能启动。在我之前对具有 64 个进程的单个仲裁器的测试中,第一个进程大约需要 0.005 秒才能启动,而第 64 个进程大约需要 0.85 秒。
【问题讨论】:
-
您正在并行运行 100 个进程。因此,每个进程都必须与所有其他进程共享您的 CPU。
-
流程本身的性能不是问题。每个过程都表现良好。这些进程的产生似乎需要越来越多的时间。
-
我不相信这不是操作系统级别的开销,与 Python 正在做的任何事情无关。使用诸如Sysdig 之类的工具来测量完成
fork()和execve()操作的实际时间可以大大消除这种怀疑。 -
(实际上尝试您提出的解决方案——拥有多个主管并查看是否发生相同的效果——同样会提供有用的数据点)。
-
...确定这是 fork 还是 execv 开销也很有趣——如果是前者,也许您的用例需要 prefork 池或类似的,在这种情况下您可能会考虑使用 Celery 进行第 3 方维护的预优化作业池实施。
标签: python python-2.7 subprocess