您不需要多个Python进程或者线程来限制最大并行子进程的数量:
from itertools import izip_longest
from subprocess import Popen, STDOUT
groups = [(Popen(cmd, stdout=outputfile, stderr=STDOUT)
for cmd in commands)] * limit
for processes in izip_longest(*groups):
for p in filter(None, processes):
p.wait()
查看 如何在Python中按n个元素的大小迭代迭代器?
如果您想限制并发子进程的最大和最小数量,可以使用线程池:
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
个子进程。
或者使用 ThreadPoolExecutor
:
from concurrent.futures import ThreadPoolExecutor
from subprocess import STDOUT, call
with ThreadPoolExecutor(max_workers=limit) as executor:
for cmd in commands:
executor.submit(call, cmd, stdout=outputfile, stderr=STDOUT)
这是一个简单的线程池实现:
import subprocess
from threading import Thread
try: from queue import Queue
except ImportError:
from Queue import Queue
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:
t.daemon = True
t.start()
for cmd in commands:
q.put_nowait(cmd)
for _ in threads: q.put(None)
for t in threads: t.join()
为避免过早退出,请添加异常处理。
如果你想把子进程的输出保存在字符串中,请参见Python:并行执行cat子进程。
multiprocessing
模块,每个工作进程都在单独的进程中生成,因此在一个工作进程中进行wait()
操作不会阻止其他工作进程运行。话虽如此,这本身并不正确--这个例子没有从工作进程中return
任何内容,因此调用结果上的.get()
不会返回任何内容。 - larskswait()
在一个工作子进程中运行。@asynts 我为你更新答案,并提供完整的示例。 - larsks