subprocess.Popen()性能随着进程数的增加而降低

时间:2018-04-12 17:27:43

标签: python python-2.7 subprocess

我有一个使用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秒。

1 个答案:

答案 0 :(得分:0)

不直接回答您关于“为什么”您正在注意到的问题,但我强烈建议您使用ThreadPoolExecutor管理系统资源来更改处理多处理的策略。

由于您的系统无法有效管理比系统线程更多的进程,我会尝试:

>>> from concurrent.futures import ThreadPoolExecutor
>>> from multiprocessing import cpu_count
>>> with ThreadPoolExecutor(workers=cpu_count()) as pool:
    results = pool.map(lambda cmd:  subprocess.Popen(cmd,stdout=subprocess.PIPE,stderr=subprocess.PIPE), command_list)

我发现API很容易,资源管理非常有效,而且“陷阱”更少。

https://docs.python.org/3.6/library/concurrent.futures.html#concurrent.futures.ThreadPoolExecutor.shutdown

虽然这是针对3.6的,但一旦pip install concurrent.futures模块为2.7,API就大致相同。