web-dev-qa-db-fra.com

Consigner la sortie du multitraitement.

Existe-t-il un moyen de consigner la sortie stdout d'un processus donné lors de l'utilisation de la classe multiprocessing.Process en python?

63
astrofrog

Le moyen le plus simple pourrait être de simplement remplacer sys.stdout. Modifiant légèrement un exemple de le manuel de multitraitement :

from multiprocessing import Process
import os
import sys

def info(title):
    print title
    print 'module name:', __name__
    print 'parent process:', os.getppid()
    print 'process id:', os.getpid()

def f(name):
    sys.stdout = open(str(os.getpid()) + ".out", "w")
    info('function f')
    print 'hello', name

if __== '__main__':
    p = Process(target=f, args=('bob',))
    p.start()
    q = Process(target=f, args=('fred',))
    q.start()
    p.join()
    q.join()

Et l'exécuter:

 $ ls 
 m.py 
 $ python m.py 
 $ ls 
 27493.out 27494 .out m.py 
 $ cat 27493.out 
 fonction f 
 nom du module: __main __ 
 processus parent: 27492 
 id du processus: 27493 
 hello bob 
 $ cat 27494.out 
 fonction f 
 nom du module: __main __ 
 processus parent: 27492 
 id de processus: 27494 
 bonjour fred 
 
50
Mark Rushakoff

Il n'y a que deux choses que j'ajouterais à la réponse de @Mark Rushakoff. Lors du débogage, j'ai trouvé très utile de changer le paramètre buffering de mes appels open() à 0.

sys.stdout = open(str(os.getpid()) + ".out", "a", buffering=0)

Sinon, folie , car quand tail -f dans le fichier de sortie, les résultats peuvent être verrouillés par intermittence. buffering=0 pour tail -f très bien.

Et pour être complet, rendez-vous service et redirigez sys.stderr ainsi que.

sys.stderr = open(str(os.getpid()) + "_error.out", "a", buffering=0)

De plus, pour plus de commodité, vous pouvez les vider dans une classe de processus distincte si vous le souhaitez,

class MyProc(Process):
    def run(self):
        # Define the logging in run(), MyProc's entry function when it is .start()-ed 
        #     p = MyProc()
        #     p.start()
        self.initialize_logging()

        print 'Now output is captured.'

        # Now do stuff...

    def initialize_logging(self):
        sys.stdout = open(str(os.getpid()) + ".out", "a", buffering=0)
        sys.stderr = open(str(os.getpid()) + "_error.out", "a", buffering=0)

        print 'stdout initialized'

Voici un Gist correspondant

15
HeyWatchThis

Vous pouvez définir sys.stdout = Logger()Logger est une classe dont la méthode write (immédiatement, ou accumulée jusqu'à ce que \n est détecté) appelle logging.info (ou tout autre moyen de connexion). n exemple de ceci en action.

Je ne sais pas ce que vous entendez par un processus "donné" (qui le donne, qu'est-ce qui le distingue de tous les autres ...?), Mais si vous voulez dire que vous savez quel processus vous voulez distinguer de cette façon au moment où vous instanciez-le, vous pouvez ensuite envelopper sa fonction target (et cela seulement) - ou la méthode run que vous remplacez dans une sous-classe Process - dans un wrapper qui effectue cette "redirection" sys.stdout - et laisse les autres processus seuls.

Peut-être que si vous fixez un peu les spécifications, je peux vous aider plus en détail ...?

11
Alex Martelli