Une note pour moi que je n'ai pas lu ou oublié même si c'était écrit dans le document.
Il est recommandé d'utiliser le module de sous-processus lors de l'exécution de processus enfants en Python.
Si vous utilisez p.stdout.read ()
ou p.stderr.read ()
lors de la réception de la sortie standard ou de la sortie d'erreur de ce processus enfant
Lorsque la quantité de données sortie par le processus enfant est importante, elle sera ** bloquée **. C'est une bonne idée d'utiliser p.communicate ()
à la place.
À ce sujet, au milieu du document suivant http://docs.python.jp/2.7/library/subprocess.html
avertissement L'utilisation de stdin.write (), stdout.read (), stderr.read () peut remplir le tampon de canal du système d'exploitation d'un autre canal et provoquer un blocage. Utilisez communique () pour éviter cela.
C'est écrit, mais c'est un mémo parce que je l'ai utilisé avec insouciance (et j'étais accro au problème).
Voici un simple code de vérification.
read ()
était OK lorsque la quantité de données de sortie du processus enfant était de 10 Ko, mais pas lorsqu'elle était de 100 Ko.
Les deux étaient OK en utilisant communiquer ()
.
spike.py
import subprocess
def bad_impl(cmd):
print "start bad_impl %s" % cmd
p = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
print "waiting"
p.wait()
stdout_data = p.stdout.read()
stderr_data = p.stderr.read()
print "finish: %d %d" % (len(stdout_data), len(stderr_data))
return p.returncode, stdout_data, stderr_data
def better_impl(cmd):
print "start better_impl %s" % cmd
p = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
print "waiting"
stdout_data, stderr_data = p.communicate()
print "finish: %d %d" % (len(stdout_data), len(stderr_data))
return p.returncode, stdout_data, stderr_data
command1 = "python -c 'print str(1) * 10000'" #Sortie 10 Ko
command2 = "python -c 'print str(1) * 100000'" #100 Ko de sortie
better_impl(command1)
print "=" * 50
bad_impl(command1)
print "=" * 50
better_impl(command2)
print "=" * 50
bad_impl(command2) #Cela échoue
% python spike.py
start better_impl python -c 'print str(1) * 10000'
waiting
finish: 10001 0
==================================================
start bad_impl python -c 'print str(1) * 10000'
waiting
finish: 10001 0
==================================================
start better_impl python -c 'print str(1) * 100000'
waiting
finish: 100001 0
==================================================
start bad_impl python -c 'print str(1) * 100000'
waiting
↑ Le contrôle ne revient pas ici
La partie communiquer ()
a également la description suivante.
Remarque Les données reçues sont mises en mémoire tampon. Par conséquent, vous ne devez pas utiliser cette méthode si les données renvoyées sont volumineuses ou illimitées.
Si vous dépassez la limite de mémoire disponible, cela est également inutile. Dans ce cas, vous devez le lire un par un et l'enregistrer dans un fichier. Si vous gérez quelques Go de données, détrompez-vous à ce moment-là ... (^^;