Maison >développement back-end >Tutoriel Python >Pourquoi mon Python `subprocess.readline` se bloque-t-il lors de la lecture d'un programme C écrivant en continu ?
Lors de la tentative de lecture de la sortie d'un programme C, à savoir "2000 ", à partir d'un script Python utilisant un sous-processus, le script se bloque à la ligne "for line in iter(process.stdout.readline, '')". Cela se produit bien que le programme C imprime continuellement "2000" et n'atteigne jamais un état final.
Le problème provient d'un problème de mise en mémoire tampon de bloc. Par défaut, la sortie standard des programmes C exécutés via des canaux (par exemple, lors de l'utilisation de subprocess.Popen) est mise en mémoire tampon. Cela signifie que les données ne sont pas vidées dans le canal tant que le tampon n'est pas plein ou explicitement vidé.
Option 1 : modifier directement le programme C
Pour résoudre le problème, vous peut forcer la mise en mémoire tampon de la sortie standard dans le programme C :
#include <stdio.h> int main() { setvbuf(stdout, (char *) NULL, _IOLBF, 0); // Make line buffered stdout while (1) { printf("2000\n"); sleep(1); } return 0; }
Option 2 : Utiliser l'utilitaire stdbuf
Vous pouvez également utiliser l'utilitaire stdbuf pour modifier le type de mise en mémoire tampon sans modifier la source du programme C :
from subprocess import Popen, PIPE process = Popen(["stdbuf", "-oL", "./main"], stdout=PIPE, bufsize=1) for line in iter(process.stdout.readline, b''): print(line) process.communicate()
Option 3 : Utiliser un pseudo-TTY
Une autre approche consiste à utiliser un pseudo-TTY pour tromper le programme C en pensant qu'il fonctionne de manière interactive :
import os import pty import sys from select import select from subprocess import Popen, STDOUT master_fd, slave_fd = pty.openpty() process = Popen("./main", stdin=slave_fd, stdout=slave_fd, stderr=STDOUT, bufsize=0, close_fds=True) timeout = .1 with os.fdopen(master_fd, 'r+b', 0) as master: input_fds = [master, sys.stdin] while True: fds = select(input_fds, [], [], timeout)[0] # Handle subprocess output and user input here
Option 4 : Utiliser pexpect
Pexpect offre une interface de niveau supérieur qui simplifie la gestion des pseudo-ATS :
import pexpect child = pexpect.spawn("./.main") for line in child: print(line) child.close()
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!