Utilisez communiquer () lors de la réception de la sortie dans un sous-processus Python

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

En outre,

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à ... (^^;

Recommended Posts

Utilisez communiquer () lors de la réception de la sortie dans un sous-processus Python
Lors de l'écriture d'un programme en Python
Utiliser l'impression dans l'expression lambda Python2
Précautions lors du décapage d'une fonction en python
Lire la sortie standard d'un sous-processus ligne par ligne en Python
Sortie sous la forme d'un tableau python
Utilisez une page d'erreur personnalisée avec python / tornado
[Question] Que se passe-t-il si vous utilisez% en python?
Utilisez pydantic lors de la lecture des variables d'environnement en Python
Utiliser des dates en Python
Utiliser Valgrind avec Python
Sortie japonaise avec Python
Utiliser le profileur en Python
Utilisez libsixel pour générer Sixel en Python et générer le graphe Matplotlib vers le terminal.
La synchronisation de la sortie est incorrecte lorsque la sortie standard (erreur) est convertie en fichier en Python
Un mémorandum lors de l'écriture de code expérimental ~ Se connecter en python
Obtenez une sortie standard en temps réel avec le sous-processus Python
Choses à noter lors de l'initialisation d'une liste en Python
Que contient cette variable (lorsque le script Python est en cours d'exécution)
Sortie japonaise lors de l'utilisation de python dans Visual Studio
Comment exécuter une commande à l'aide d'un sous-processus en Python
Un modèle personnellement utilisé pour créer Discord BOT en Python (Notes)
Voyons comment utiliser def en python
Prendre une capture d'écran en Python
Utiliser l'expression let en Python
Utiliser le protocole de mesure avec Python
Créer une fonction en Python
Créer un dictionnaire en Python
Utiliser la fonction de rappel en Python
Utiliser le magasin de paramètres en Python
[Python] Utiliser une séquence de chaînes
Utiliser le cache HTTP en Python
Utilisez l'ODM de MongoDB avec Python
Utiliser un dict clé de liste en Python
Utiliser Random Forest avec Python
Utilisez Spyder de Python IDE
Créer un bookmarklet en Python
Attention lorsque os.mkdir en Python
Dessinez un cœur en Python
Lire la sortie Fortran avec python
[Django] Mémorandum lorsque vous souhaitez communiquer de manière asynchrone [Python3]
Comment utiliser la méthode __call__ dans la classe Python
Changer la destination de sortie standard en un fichier en Python
Comportement en donnant une liste avec shell = True dans le sous-processus
[python] Remarques lors de la tentative d'utilisation de numpy avec Cython
Utilisez une macro qui s'exécute lors de l'enregistrement de python avec vscode
Une note lors de la création d'un graphe dirigé à l'aide de Graphviz en Python
[Selenium] Changer la destination de sortie du journal lors de l'exécution de phantomjs avec python3
Notification Slack lorsqu'un mot spécifique est murmuré sur Twitter en utilisant Heroku avec python
[Sous-processus] Lorsque vous souhaitez exécuter un autre programme Python en code Python
Probablement dans un serpent Nishiki (Titre original: Peut-être en Python)
Convertir en chaîne lors de la sortie de la sortie standard avec le sous-processus Python
Ecrire une dichotomie en Python
[python] Gérer les fonctions dans une liste
Précautions lors de l'utilisation de Pit avec Python
Appuyez sur une commande en Python (Windows)
Utilisez le tissu tel quel en python (fabric3)
Créer un conteneur DI avec Python
Comportement lors de la liste dans Python heapq
Utilisez networkx, une bibliothèque qui gère les graphiques en python (Partie 2: Tutoriel)