Python subprocesando múltiples subprocesos de bash?

¿Cómo se utilizan los módulos de subprocesos y subprocesos para generar procesos de bash paralelos? Cuando empiezo los hilos, la primera respuesta es aquí: ¿Cómo usar los hilos en Python? , los procesos de bash se ejecutan secuencialmente en lugar de en paralelo.

No necesitas hilos para ejecutar subprocesos en paralelo:

from subprocess import Popen commands = [ 'date; ls -l; sleep 1; date', 'date; sleep 5; date', 'date; df -h; sleep 3; date', 'date; hostname; sleep 2; date', 'date; uname -a; date', ] # run in parallel processes = [Popen(cmd, shell=True) for cmd in commands] # do other things here.. # wait for completion for p in processes: p.wait() 

Para limitar el número de comandos concurrentes, puede usar multiprocessing.dummy.Pool que usa subprocesos y proporciona la misma interfaz que multiprocessing.Pool que usa procesos:

 from functools import partial from multiprocessing.dummy import Pool from subprocess import call pool = Pool(2) # two concurrent commands at a time for i, returncode in enumerate(pool.imap(partial(call, shell=True), commands)): if returncode != 0: print("%d command failed: %d" % (i, returncode)) 

Esta respuesta demuestra varias técnicas para limitar el número de subprocesos concurrentes : muestra multiproceso .Pool, concurrent.futures, threading + Queue-baseded solutions.


Podría limitar el número de procesos secundarios simultáneos sin utilizar un grupo de subprocesos / procesos:

 from subprocess import Popen from itertools import islice max_workers = 2 # no more than 2 concurrent processes processes = (Popen(cmd, shell=True) for cmd in commands) running_processes = list(islice(processes, max_workers)) # start new processes while running_processes: for i, process in enumerate(running_processes): if process.poll() is not None: # the process has finished running_processes[i] = next(processes, None) # start new process if running_processes[i] is None: # no new processes del running_processes[i] break 

En Unix, podría evitar el ciclo de ocupado y el locking en os.waitpid(-1, 0) , para esperar a que salga cualquier proceso secundario .

Un ejemplo simple de enhebrado:

 import threading import Queue import commands import time # thread class to run a command class ExampleThread(threading.Thread): def __init__(self, cmd, queue): threading.Thread.__init__(self) self.cmd = cmd self.queue = queue def run(self): # execute the command, queue the result (status, output) = commands.getstatusoutput(self.cmd) self.queue.put((self.cmd, output, status)) # queue where results are placed result_queue = Queue.Queue() # define the commands to be run in parallel, run them cmds = ['date; ls -l; sleep 1; date', 'date; sleep 5; date', 'date; df -h; sleep 3; date', 'date; hostname; sleep 2; date', 'date; uname -a; date', ] for cmd in cmds: thread = ExampleThread(cmd, result_queue) thread.start() # print results as we get them while threading.active_count() > 1 or not result_queue.empty(): while not result_queue.empty(): (cmd, output, status) = result_queue.get() print('%s:' % cmd) print(output) print('='*60) time.sleep(1) 

Tenga en cuenta que hay mejores maneras de hacer algo de esto, pero esto no es demasiado complicado. El ejemplo utiliza un hilo para cada comando. La complejidad comienza a aparecer cuando quieres hacer cosas como usar un número limitado de subprocesos para manejar un número desconocido de comandos. Esas técnicas más avanzadas no parecen demasiado complicadas una vez que tienes un conocimiento de los conceptos básicos de enhebrado. Y el multiprocesamiento se vuelve más fácil una vez que tienes un manejo de esas técnicas.

esto se debe a que se supone que debe hacer, lo que se desea hacer no es el multiprocesamiento sino el multiprocesamiento, vea esta página de stack