Maison > développement back-end > Tutoriel Python > Comment éviter que les programmes Python ne se bloquent lors de la lecture de la sortie du processus ?

Comment éviter que les programmes Python ne se bloquent lors de la lecture de la sortie du processus ?

Susan Sarandon
Libérer: 2024-11-02 13:54:29
original
526 Les gens l'ont consulté

How to Avoid Python Programs from Hanging When Reading Process Output?

Arrêter de lire la sortie du processus en Python sans blocage ?

Problème :

Un programme Python doit interagir avec un programme externe processus (par exemple, « top ») qui produit en continu une sortie. Cependant, la simple lecture directe de la sortie peut provoquer le blocage du programme indéfiniment.

Solution :

Pour éviter le blocage, il est essentiel d'utiliser des mécanismes non bloquants ou asynchrones lorsque sortie du processus de lecture. Voici quelques approches possibles :

Fichier temporaire spoolé (recommandé)

Cette méthode utilise un objet fichier dédié pour stocker la sortie du processus.

# ! /usr/bin/env python<br>import subprocess<br>import tempfile<br>import time</p>
<p>def main():</p>
<div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false"># Open a temporary file (automatically deleted on closure)
f = tempfile.TemporaryFile()

# Start the process and redirect stdout to the file
p = subprocess.Popen(["top"], stdout=f)

# Wait for a specified duration
time.sleep(2)

# Kill the process
p.terminate()
p.wait()

# Rewind and read the captured output from the file
f.seek(0)
output = f.read()

# Print the output
print(output)
f.close()
Copier après la connexion

if nom == "__main__":

main()
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion

Lecture de sortie basée sur les threads

Cette approche utilise un thread séparé pour lire en continu la sortie du processus tout en le thread principal poursuit d'autres tâches.

import collections<br>import subprocess<br>import threading<br>import time</p>
<p>def read_output(process, append):</p>
<div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false">for line in iter(process.stdout.readline, ""):
    append(line)
Copier après la connexion

def main():

# Start the process and redirect stdout
process = subprocess.Popen(["top"], stdout=subprocess.PIPE, close_fds=True)

# Create a thread for output reading
q = collections.deque(maxlen=200)
t = threading.Thread(target=read_output, args=(process, q.append))
t.daemon = True
t.start()

# Wait for the specified duration
time.sleep(2)

# Print the saved output
print(''.join(q))
Copier après la connexion

if nom == "__main__":

main()
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion

signal.alarm() (Unix uniquement)

Cette méthode utilise des signaux Unix pour terminer le processus après un délai d'attente spécifié, que toutes les sorties aient été lues ou non.

importer des collections<br>signal d'importation<br>sous-processus d'importation</p>
<p>class Alarm(Exception):</p>
<div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false">pass
Copier après la connexion

def alarm_handler(signum, frame):

raise Alarm
Copier après la connexion

def main():

# Start the process and redirect stdout
process = subprocess.Popen(["top"], stdout=subprocess.PIPE, close_fds=True)

# Set signal handler
signal.signal(signal.SIGALRM, alarm_handler)
signal.alarm(2)

try:
    # Read and save a specified number of lines
    q = collections.deque(maxlen=200)
    for line in iter(process.stdout.readline, ""):
        q.append(line)
    signal.alarm(0)  # Cancel alarm
except Alarm:
    process.terminate()
finally:
    # Print the saved output
    print(''.join(q))
Copier après la connexion

if nom == "__main__":

main()
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion

threading.Timer

Cette approche utilise une minuterie pour terminer le processus après un délai d'attente spécifié. Il fonctionne à la fois sur les systèmes Unix et Windows.

import collections<br>import subprocess<br>import threading</p>
<p>def main():</p>
<div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false"># Start the process and redirect stdout
process = subprocess.Popen(["top"], stdout=subprocess.PIPE, close_fds=True)

# Create a timer for process termination
timer = threading.Timer(2, process.terminate)
timer.start()

# Read and save a specified number of lines
q = collections.deque(maxlen=200)
for line in iter(process.stdout.readline, ""):
    q.append(line)
timer.cancel()

# Print the saved output
print(''.join(q))
Copier après la connexion

if name == "__main__":

main()
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion

Aucun fil de discussion, aucun signal

Cette méthode utilise un boucle temporelle simple pour vérifier la sortie du processus et la tuer si elle dépasse un délai d'attente spécifié.

import collections<br>import subprocess<br>import sys<br>import time</p> <p>def main():</p>
<div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false">args = sys.argv[1:]
if not args:
    args = ['top']

# Start the process and redirect stdout
process = subprocess.Popen(args, stdout=subprocess.PIPE, close_fds=True)

# Save a specified number of lines
q = collections.deque(maxlen=200)

# Set a timeout duration
timeout = 2

now = start = time.time()
while (now - start) < timeout:
    line = process.stdout.readline()
    if not line:
        break
    q.append(line)
    now = time.time()
else:  # On timeout
    process.terminate()

# Print the saved output
print(''.join(q))
Copier après la connexion

if nom == "__main__":

main()
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion

Remarque : Le nombre de lignes stockées peut être ajusté selon les besoins en définissant le paramètre 'maxlen' de la structure de données deque.

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

source:php.cn
Article précédent:Pouvez-vous rajeunir un objet générateur Python pour le réutiliser ? Article suivant:Comment ignorer des lignes spécifiques lors de l'importation de fichiers CSV avec Pandas ?
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Derniers articles par auteur
Derniers numéros
Rubriques connexes
Plus>
Recommandations populaires
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal