Maison > développement back-end > Tutoriel Python > Pourquoi `subprocess.readlines()` se bloque-t-il lors de la diffusion d'un fichier Ruby en Python ?

Pourquoi `subprocess.readlines()` se bloque-t-il lors de la diffusion d'un fichier Ruby en Python ?

Mary-Kate Olsen
Libérer: 2024-12-06 12:59:15
original
930 Les gens l'ont consulté

Why Does `subprocess.readlines()` Hang When Streaming a Ruby File in Python?

Python subprocess.readlines() se bloque

Problème :

Dans le code Python suivant , l'utilisation de subprocess.readlines() pour diffuser un fichier Ruby provoque le blocage du programme indéfiniment, empêchant l'instruction d'impression finale d'être exécuté :

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

file_path = '/Users/luciano/Desktop/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 is never reached!")
Copier après la connexion

Cause :

Le problème ici provient de l'utilisation de pty, qui est destiné à la gestion du pseudo-terminal. Cela provoque généralement une mise en mémoire tampon de ligne du côté Ruby, ce qui fait que la fonction readline() attend indéfiniment un caractère de nouvelle ligne.

Solutions :

Il existe plusieurs options pour résoudre ce problème :

1. Utilisation de pexpect :

pexpect active la mise en mémoire tampon de ligne dans un cadre non interactif :

import sys
import pexpect

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

2. Utilisation de stdbuf :

stdbuf peut être utilisé pour activer 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

3. Utilisation de pty depuis la bibliothèque standard :

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

master_fd, slave_fd = pty.openpty()  # provide tty to enable
                                     # line-buffering on ruby's side
proc = Popen(['ruby', 'ruby_sleep.rb'],
             stdin=slave_fd, stdout=slave_fd, stderr=STDOUT, close_fds=True)
os.close(slave_fd)
try:
    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
Derniers articles par auteur
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal