Maison > développement back-end > Tutoriel Python > Pourquoi le « subprocess.Popen » de Python avec « readlines() » se bloque-t-il et comment puis-je le réparer ?

Pourquoi le « subprocess.Popen » de Python avec « readlines() » se bloque-t-il et comment puis-je le réparer ?

DDD
Libérer: 2024-12-03 10:37:10
original
191 Les gens l'ont consulté

Why Does Python's `subprocess.Popen` with `readlines()` Hang, and How Can I Fix It?

Le sous-processus Python readlines() Problème de blocage

Introduction

La diffusion en continu d'un fichier et l'impression de la sortie ligne par ligne peuvent être réalisées en utilisant diverses méthodes. Cependant, l'utilisation d'un sous-processus avec readlines() peut entraîner des problèmes de blocage.

Le script Python

Considérez le script Python "main.py" conçu pour diffuser un fichier Ruby "ruby_sleep.rb" et imprimer sa sortie.

import pty
import os
from subprocess import Popen, PIPE, STDOUT

file_path = '/path/to/ruby_sleep.rb'
command = ' '.join(["ruby", file_path])

master, slave = pty.openpty()
proc = Popen(command, bufsize=0, shell=True, stdout=slave, stderr=slave, close_fds=True)     
stdout = os.fdopen(master, 'r', 0)

while proc.poll() is None:
    data = stdout.readline()
    if data != "":
        print(data)
    else:
        break

print("This line is never reached")
Copier après la connexion

Le problème et les observations

L'exécution de ce script diffuse la sortie Ruby sous la forme attendu, mais la méthode readline() se bloque indéfiniment, ce qui fait que la chaîne « Cette ligne n'est jamais atteinte » n'est jamais imprimée.

Approches de solution

Diverses solutions ont été proposées pour résoudre ce problème de blocage. :

1. L'utilisation de Stdbuf

Stdbuf permet la mise en mémoire tampon de ligne en mode non interactif.

from subprocess import Popen, PIPE, STDOUT

proc = Popen(['stdbuf', '-oL', 'ruby', 'ruby_sleep.rb'],
             bufsize=1, stdout=PIPE, stderr=STDOUT, close_fds=True)
for line in iter(proc.stdout.readline, b''):
    print line,
proc.stdout.close()
proc.wait()
Copier après la connexion

2. Utilisation de Pexpect

Pexpect peut être utilisé pour un contrôle basé sur la ligne.

import pexpect

pexpect.run("ruby ruby_sleep.rb", logfile=sys.stdout)
Copier après la connexion

3. L'utilisation de PTY

PTY permet de fournir un terminal pour activer la mise en mémoire tampon de ligne côté Ruby.

import os
import pty
from subprocess import Popen, STDOUT

master_fd, slave_fd = pty.openpty()
proc = Popen(['ruby', 'ruby_sleep.rb'],
             stdin=slave_fd, stdout=slave_fd, stderr=STDOUT, close_fds=True)
os.close(slave_fd)
while 1:
    try:
        data = os.read(master_fd, 512)
    except OSError as e:
        if e.errno != errno.EIO:
            raise
        break # EIO means EOF on some systems
    else:
        if not data: # EOF
            break
        print('got ' + repr(data))
finally:
    os.close(master_fd)
    if proc.poll() is None:
        proc.kill()
    proc.wait()
    print("This is reached!")
Copier après la connexion

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
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
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal