Pregunta

Tengo una pregunta general sobre popen (y todas las funciones relacionadas), aplicable a todos los sistemas operativos, cuando escribo un script en Python o algún código c y ejecuto el ejecutable resultante desde la consola (win o linux), puedo Ver el resultado del proceso. Sin embargo, si ejecuto el mismo ejecutable que un proceso bifurcado con su stdout redirigido a una canalización, la salida se almacena en algún lugar, generalmente hasta 4096 bytes antes de que se escriba en la tubería donde el proceso principal puede leerlo.

La siguiente secuencia de comandos de Python generará una salida en trozos de 1024 bytes

import os, sys, time

if __name__ == "__main__":
     dye = '@'*1024
     for i in range (0,8):
        print dye
        time.sleep(1)

La siguiente secuencia de comandos de Python ejecutará la secuencia de comandos anterior y leerá la salida tan pronto como llegue a la tubería, byte a byte

import os, sys, subprocess, time, thread

if __name__ == "__main__":
    execArgs = ["c:\\python25\\python.exe", "C:\\Scripts\\PythonScratch\\byte_stream.py"]

    p = subprocess.Popen(execArgs, bufsize=0, stdout=subprocess.PIPE)
    while p.returncode == None:
        data = p.stdout.read(1)
        sys.stdout.write(data)
        p.poll()

Ajusta la ruta para tu sistema operativo. Cuando se ejecuta en esta configuración, la salida no aparecerá en los bloques de 1024, sino en los de 4096, a pesar de que el tamaño del búfer del comando popen se establece en 0 (que es el valor predeterminado de todos modos). ¿Alguien puede decirme cómo cambiar este comportamiento? ¿Hay alguna manera en que pueda forzar al sistema operativo a tratar la salida del proceso bifurcado de la misma manera que cuando se ejecuta desde la consola ?, es decir, simplemente alimenta los datos a través de sin buffering?

¿Fue útil?

Solución

En general, la biblioteca de tiempo de ejecución de C estándar (que se ejecuta en nombre de casi todos los programas en cada sistema, más o menos ;-) detecta si stdout es un terminal o no; de lo contrario, amortigua la salida (lo que puede ser una gran ganancia de eficiencia, en comparación con la salida sin búfer).

Si tienes el control del programa que está haciendo la escritura, puedes (como sugiere otra respuesta) vaciar la salida estándar de forma continua, o (más elegantemente si es posible) tratar de forzar la salida estándar para que no tenga un buffer, por ejemplo ejecutando Python con el indicador de línea de comando -u :

-u     : unbuffered binary stdout and stderr (also PYTHONUNBUFFERED=x)
         see man page for details on internal buffering relating to '-u'

(lo que agrega la página de manual es una mención de la entrada estándar y los problemas con el modo binario [s]).

Si no puede o no quiere tocar el programa que está escribiendo, -u o similar en el programa que está leyendo es poco probable que ayude (el almacenamiento en búfer que más importa es el uno sucediendo en la entrada del escritor, no en la lectura del lector). La alternativa es engañar al escritor para que crea que está escribiendo en un terminal (¡aunque en realidad está escribiendo en otro programa!), A través del módulo de biblioteca estándar pty o el tercero de más alto nivel pexpect módulo (o, para Windows, su puerto wexpect ).

Otros consejos

Eso es correcto, y se aplica tanto a Windows como a Linux (y posiblemente a otros sistemas), con popen () y fopen () . Si desea que el búfer de salida se envíe antes de 4096 bytes, use fflush () (en C) o sys.stdout.flush () (Python).

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top