Subproceso de python persistente

¿Hay una manera de hacer una llamada de subproceso en python “persistente”? Estoy llamando a un progtwig que tarda un tiempo en cargarse varias veces. Así que sería genial si pudiera dejar ese progtwig abierto y comunicarme con él sin matarlo.

La versión de dibujos animados de mi script de python se ve así:

for text in textcollection: myprocess = subprocess.Popen(["myexecutable"], stdin = subprocess.PIPE, stdout = subprocess.PIPE, stderr = None) myoutputtext, err = myprocess.communicate(input=text) 

Necesito procesar cada texto por separado, así que unirlo todo en un archivo de texto grande y procesarlo una vez no es una opción.

Preferiblemente, si hay una opción como esta.

 myprocess = subprocess.Popen(["myexecutable"], stdin = subprocess.PIPE, stdout = subprocess.PIPE, stderr = None) for text in textcollection: for text in textcollection: myoutputtext, err = myprocess.communicate(input=text) 

Donde puedo dejar el proceso abierto, realmente lo apreciaría.

Puede usar myprocess.stdin.write() y myprocess.stdout.read() para comunicarse con su subproceso, solo debe tener cuidado para asegurarse de manejar el almacenamiento en búfer correctamente para evitar que sus llamadas se bloqueen.

Si la salida de su subproceso está bien definida, debería poder comunicarse de manera confiable con él utilizando el búfer de línea y myprocess.stdout.readline() .

Aquí hay un ejemplo:

 >>> p = subprocess.Popen(['cat'], bufsize=1, stdin=subprocess.PIPE, stdout=subprocess.PIPE) >>> p.stdin.write('hello world\n') >>> p.stdout.readline() 'hello world\n' >>> p.stdout.readline() # THIS CALL WILL BLOCK 

Una alternativa a este método para Unix es poner el manejador de archivos en modo no bloqueante, que le permitirá llamar a funciones como myprocess.stdout.read() y devolverle los datos si hay alguno disponible, o generar un IOError si existe no es ningún dato

 >>> p = subprocess.Popen(['cat'], stdin=subprocess.PIPE, stdout=subprocess.PIPE) >>> import fcntl, os >>> fcntl.fcntl(p.stdout.fileno(), fcntl.F_SETFL, os.O_NONBLOCK) 0 >>> p.stdout.read() # raises an exception instead of blocking Traceback (most recent call last): File "", line 1, in  IOError: [Errno 11] Resource temporarily unavailable 

Esto te permitiría hacer algo como esto:

 fcntl.fcntl(p.stdout.fileno(), fcntl.F_SETFL, os.O_NONBLOCK) for text in textcollection: myprocess.stdin.write(text + '\n') while True: myoutputtext = '' try: myoutputtext += myprocess.stdout.read() except IOError: pass if validate_output(myoutputtext): break time.sleep(.1) # short sleep before attempting another read 

En este ejemplo, validate_output() es una función que necesitaría escribir que devuelva True si los datos que ha recibido hasta ahora son todos los resultados que espera obtener.

Es la llamada a communicate() que está matando a su subproceso. De acuerdo con la documentación del subproceso, el método communicate() :

Interactuar con el proceso: Enviar datos a stdin. Lea los datos de stdout y stderr, hasta que se scope el final del archivo. Espere a que termine el proceso.

Lo que quiere hacer es interactuar directamente con las POpen stdin y stdout del objeto POpen directamente para comunicarse con el subproceso. Sin embargo, la documentación desaconseja este dicho:

Advertencia: use comunicarse () en lugar de .stdin.write, .stdout.read o .stderr.read para evitar puntos muertos debido a que cualquiera de los otros buffers de tuberías del sistema operativo se llene y bloquee el proceso secundario.

Por lo tanto, debe implementar sus propias soluciones para posibles interlockings o esperar que alguien haya escrito un módulo de subproceso asíncrono para usted.

Edición: Este es un ejemplo rápido de cómo se podría usar el módulo de subproceso asíncrono:

 import asyncsubprocess textcollection = ['to', 'be', 'or', 'not', 'to be', 'that is the', 'question'] myprocess = asyncsubprocess.Popen(["cat"], stdin = asyncsubprocess.PIPE, stdout = asyncsubprocess.PIPE, stderr = None) for text in textcollection: bytes_sent, myoutput, err = myprocess.listen(text) print text, bytes_sent, myoutput, err 

Cuando ejecuto esto, se imprime:

 to 2 to be 2 be or 2 or not 3 not to be 5 to be that is the 11 that is the question 8 question 

Creo que estas buscando

 myprocess.stdin.write(text) 

puede crear una lista de Popens y luego llamar a comunicarse en cada elemento en otro bucle. algo como esto

 processes=[] for text in textcollection: myprocess = subprocess.Popen(["myexecutable"], stdin = subprocess.PIPE, stdout = subprocess.PIPE, stderr = None) myprocess.stdin.write(text) processes.append(myprocess) for proc in processes: myoutput, err=proc.communicate() #do something with the output here 

De esta manera no tendrá que esperar hasta que todos los Popens hayan comenzado.

 if os.name == 'nt': startupinfo = subprocess.STARTUPINFO() startupinfo.dwFlags |= subprocess._subprocess.STARTF_USESHOWWINDOW subprocess.call(os.popen(tempFileName), shell=True) os.remove(tempFileName)