控制用于在python中调用外部命令的子进程数

控制用于在python中调用外部命令的子进程数,python,parallel-processing,subprocess,multiprocessing,Python,Parallel Processing,Subprocess,Multiprocessing,我知道使用是调用外部命令的首选方式 但是,如果我想并行运行几个命令,但限制生成的进程数量,该怎么办?困扰我的是我无法阻止子进程。例如,如果我打电话 subprocess.Popen(cmd, stderr=outputfile, stdout=outputfile) 然后,该过程将继续,而无需等待cmd完成。因此,我不能将其封装在多处理库的worker中 例如,如果我这样做: def worker(cmd): subprocess.Popen(cmd, stderr=outputfi

我知道使用是调用外部命令的首选方式

但是,如果我想并行运行几个命令,但限制生成的进程数量,该怎么办?困扰我的是我无法阻止子进程。例如,如果我打电话

subprocess.Popen(cmd, stderr=outputfile, stdout=outputfile)
然后,该过程将继续,而无需等待
cmd
完成。因此,我不能将其封装在
多处理
库的worker中

例如,如果我这样做:

def worker(cmd): 
    subprocess.Popen(cmd, stderr=outputfile, stdout=outputfile);

pool = Pool( processes = 10 );
results =[pool.apply_async(worker, [cmd]) for cmd in cmd_list];
ans = [res.get() for res in results];
然后,每个工作进程将完成并在生成子进程后返回。因此,我不能通过使用
来限制
子流程生成的进程数


限制子流程数量的正确方法是什么

如果要等待命令完成,可以使用
子流程。调用
。有关更多信息,请参阅

您还可以在worker中调用该方法:

def worker(cmd): 
    p = subprocess.Popen(cmd, stderr=outputfile, stdout=outputfile);
    p.wait()

您不需要多个Python进程甚至线程来限制并行子进程的最大数量:

from itertools import izip_longest
from subprocess import Popen, STDOUT

groups = [(Popen(cmd, stdout=outputfile, stderr=STDOUT)
          for cmd in commands)] * limit # itertools' grouper recipe
for processes in izip_longest(*groups): # run len(processes) == limit at a time
    for p in filter(None, processes):
        p.wait()

如果要限制并行子进程的最大和最小数量,可以使用线程池:

from multiprocessing.pool import ThreadPool
from subprocess import STDOUT, call

def run(cmd):
    return cmd, call(cmd, stdout=outputfile, stderr=STDOUT)

for cmd, rc in ThreadPool(limit).imap_unordered(run, commands):
    if rc != 0:
        print('{cmd} failed with exit status: {rc}'.format(**vars()))
只要任何
limit
子流程结束,就会启动一个新的子流程,以始终保持
limit
子流程的数量

或使用:

下面是一个简单的线程池实现:

import subprocess
from threading import Thread

try: from queue import Queue
except ImportError:
    from Queue import Queue # Python 2.x


def worker(queue):
    for cmd in iter(queue.get, None):
        subprocess.check_call(cmd, stdout=outputfile, stderr=subprocess.STDOUT)

q = Queue()
threads = [Thread(target=worker, args=(q,)) for _ in range(limit)]
for t in threads: # start workers
    t.daemon = True
    t.start()

for cmd in commands:  # feed commands to threads
    q.put_nowait(cmd)

for _ in threads: q.put(None) # signal no more commands
for t in threads: t.join()    # wait for completion
为避免过早退出,请添加异常处理


如果要以字符串形式捕获子流程的输出,请参阅。

这将完全禁用并行处理,但不应如此。问题是使用
多处理
模块,每个工作进程都在一个单独的进程中生成,因此在一个工作进程中生成
wait()
不会阻止其他工作进程运行。这就是说,这本身是不正确的——这个示例不会
从worker返回任何内容,因此对结果调用
.get()
不会返回任何内容。
import subprocess
from threading import Thread

try: from queue import Queue
except ImportError:
    from Queue import Queue # Python 2.x


def worker(queue):
    for cmd in iter(queue.get, None):
        subprocess.check_call(cmd, stdout=outputfile, stderr=subprocess.STDOUT)

q = Queue()
threads = [Thread(target=worker, args=(q,)) for _ in range(limit)]
for t in threads: # start workers
    t.daemon = True
    t.start()

for cmd in commands:  # feed commands to threads
    q.put_nowait(cmd)

for _ in threads: q.put(None) # signal no more commands
for t in threads: t.join()    # wait for completion