web-dev-qa-db-fra.com

Python enfiler plusieurs sous-processus bash?

Comment utilise-t-on les modules de thread et de sous-processus pour générer des processus bash parallèles? Quand je démarre les threads, la première réponse ici est la suivante: Comment utiliser le threading en Python? , les processus bash s'exécutent séquentiellement plutôt qu'en parallèle.

34
Andrew

Vous n'avez pas besoin de threads pour exécuter des sous-processus en parallèle:

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()

Pour limiter le nombre de commandes simultanées, vous pouvez utiliser multiprocessing.dummy.Pool Qui utilise des threads et fournit la même interface que multiprocessing.Pool qui utilise des processus:

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))

Cette réponse montre différentes techniques pour limiter le nombre de sous-processus simultanés : elle montre le multiprocessing.Pool, concurrent.futures, threading + Queue-based solutions.


Vous pouvez limiter le nombre de processus enfants simultanés sans utiliser de pool de threads/processus:

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

Sous Unix, vous pouvez éviter la boucle occupée et bloquer sur os.waitpid(-1, 0), attendre que tout processus enfant se termine .

57
jfs

Un exemple de filetage simple:

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)

Notez qu'il existe de meilleures façons de faire cela, mais ce n'est pas trop compliqué. L'exemple utilise un thread pour chaque commande. La complexité commence à s'introduire lorsque vous voulez faire des choses comme utiliser un nombre limité de threads pour gérer un nombre inconnu de commandes. Ces techniques plus avancées ne semblent pas trop compliquées une fois que vous maîtrisez les bases du filetage. Et le multitraitement devient plus facile une fois que vous maîtrisez ces techniques.

6
rzzzwilson

c'est parce qu'il est censé le faire, la chose que vous voulez faire n'est pas du multithreading mais du multiprocessing voir ceci page de pile

0
Magaly Alonzo