2012-01-23 13 views
13

Estoy tratando de crear una secuencia de comandos que utiliza el módulo de multiprocesamiento con python. El script (vamos a llamarlo myscript.py) obtendrá la entrada de otro script con pipe.¿Hay alguna manera de pasar 'stdin' como argumento a otro proceso en python?

Supongamos que llamo a los scripts de esta manera;

$ python writer.py | python myscript.py 

Y aquí están los códigos;

// writer.py 
import time, sys 

def main(): 
    while True: 
     print "test" 
     sys.stdout.flush() 
     time.sleep(1) 

main() 

//myscript.py 
def get_input(): 
    while True: 
     text = sys.stdin.readline() 
     print "hello " + text 
     time.sleep(3) 

if __name__ == '__main__':   
    p1 = Process(target=get_input, args=()) 
    p1.start() 

esto claramente no funciona, ya que los objetos sys.stdin son diferentes para el proceso principal y p1. Así que he intentado esto para resolverlo,

//myscript.py 
def get_input(temp): 
    while True: 
     text = temp.readline() 
     print "hello " + text 
     time.sleep(3) 

if __name__ == '__main__':   
    p1 = Process(target=get_input, args=(sys.stdin,)) 
    p1.start() 

pero me encuentro con este error;

Process Process-1: 
Traceback (most recent call last): 
    File "/usr/lib/python2.7/multiprocessing/process.py", line 258, in _bootstrap 
    self.run() 
    File "/usr/lib/python2.7/multiprocessing/process.py", line 114, in run 
    self._target(*self._args, **self._kwargs) 
    File "in.py", line 12, in get_input 
    text = temp.readline() 
ValueError: I/O operation on closed file 

Así que, supongo que el archivo stdin de main está cerrado y no puedo leer de él. En esta conjunción, ¿cómo puedo pasar el archivo stdin de main a otro proceso? Si no es posible pasar stdin, ¿cómo puedo usar el stdin de main de otro proceso?

actualización: Bien, necesito aclarar mi pregunta ya que la gente piensa que usar el multiprocesamiento no es realmente necesario. considere myscript.py de esta manera;

//myscript.py 
def get_input(): 
    while True: 
     text = sys.stdin.readline() 
     print "hello " + text 
     time.sleep(3) 

def do_more_things(): 
    while True: 
     #// some code here 
     time.sleep(60*5) 

if __name__ == '__main__':   
    p1 = Process(target=get_input, args=()) 
    p1.start() 

    do_more_things() 

es así, que realmente necesita para funcionar get_input() de forma paralela con la función principal (u otros subprocesos). Disculpe por los conflictos, tengo un inglés decente, y creo que no pude aclarar esta pregunta. Les agradecería si me pueden decir si puedo usar el proceso principal objeto STDIN en otro proceso.

gracias de antemano.

+1

puede escribir a la entrada estándar usando la sintaxis encontrado aquí http://stackoverflow.com/questions/ 8880461/python-subprocess-output-to-list-or-file/8880555 # 8880555 Allí se usa para leer pero puede usar los mismos objetos –

+0

¿Por qué 'myscript.py' crea un subproceso? ¿Por qué no simplemente lee de sys.stdin? Si lee de 'sys.stdin' el script de shell funcionaría perfectamente. ¿Por qué crear un subproceso? –

+0

Hola S.Lott, este es solo un prototipo de mi problema, myscript.py contiene otro proceso que tiene otro ciclo infinito y se ejecuta como un daemon, así que simplemente no puedo leerlo en el proceso principal de myscript ya que writer.py también infinito y necesita ejecutarse como daemon. @JohanLundberg, gracias por su consejo, lo verificaré. –

Respuesta

9

Lo más sencillo es para intercambiar get_input() y do_more_things() es decir, lee sys.stdin en el proceso padre:

def get_input(stdin): 
    for line in iter(stdin.readline, ''): 
     print("hello", line, end='') 
    stdin.close() 

if __name__ == '__main__': 
    p1 = mp.Process(target=do_more_things) 
    p1.start() 
    get_input(sys.stdin) 

La siguiente mejor opción es usar Thread() en lugar de.210 para get_input():

if __name__ == '__main__': 
    t = Thread(target=get_input, args=(sys.stdin,)) 
    t.start() 
    do_more_things() 

Si lo anterior no ayuda usted podría intentar os.dup():

newstdin = os.fdopen(os.dup(sys.stdin.fileno())) 
try: 
    p = Process(target=get_input, args=(newstdin,)) 
    p.start()  
finally: 
    newstdin.close() # close in the parent 
do_more_things() 
+0

aunque solo necesitaba una tercera, las otras soluciones funcionan bastante bien. gracias por tomarse el tiempo y ayudar de manera comprensiva. –

2

Cada nuevo proceso creado con el módulo de multiprocesamiento tiene su propio PID, y por lo tanto su propio dispositivo de entrada y dispositivos de salida, incluso si ambos escriben en el mismo terminal, de ahí la necesidad de bloqueos.

Ya está creando dos procesos separando el contenido en dos scripts y creando un tercer proceso con get_input(). get_input podría leer la entrada estándar si fuera un hilo en lugar de un proceso. Entonces, no es necesario tener una función de suspensión en el lector.

## reader.py 
from threading import Thread 
import sys 

def get_input(): 
    text = sys.stdin.readline() 
    while len(text) != 0: 
     print 'hello ' + text 
     text = sys.stdin.readline() 

if __name__ == '__main__': 
    thread = Thread(target=get_input) 
    thread.start() 
    thread.join() 
2

Esto solo será una respuesta parcial, ya que no tengo claro las siguientes partes de la pregunta.

Usted empezar por decir que usted anticipa que llamar a las secuencias de comandos:

$ python writer.py | python myscript.py 

Si vas a hacer eso, el escritor tiene que escribir en la salida estándar y miscript tiene que leer de la entrada estándar. El segundo script se vería así:

def get_input(): 
    while True: 
     text = sys.stdin.readline() 
     print "hello " + text 
     time.sleep(3) 
if __name__ == '__main__':  
    get_input() 

No hay necesidad del objeto multiprocesamiento.Proceso ...ya está ejecutando dos procesos desde la línea de comandos, y está utilizando el intérprete de comandos para conectarlos con un conducto (anónimo) (el carácter "|") que conecta la salida estándar del primer guión a la entrada estándar del segundo guión.

El objetivo del objeto Proceso es gestionar el inicio de un segundo proceso desde el primero. Necesitarías definir un proceso; luego inícielo, entonces probablemente quiera esperar hasta que haya terminado antes de salir del primer proceso ... (llamar a p1.join() después de p1.start() sería suficiente para esto).

Si desea comunicarse entre un par de procesos bajo el control de python, probablemente desee utilizar el objeto multiprocess.Pipe para hacerlo. A continuación, puede comunicarse fácilmente entre el proceso generado inicial y subordinado leyendo y escribiendo en/desde el objeto Pipe en lugar de la entrada estándar y la salida estándar. Si realmente desea redirigir la entrada estándar y la salida estándar, esto probablemente sea posible al jugar con descriptores de archivos de bajo nivel y/o anular/reemplazar los objetos sys.stdin y sys.stdout ... pero, sospecho , probablemente no quieras (o necesites) hacer esto.

1

Para leer el hilo en el uso de insumos fileinput:

myscript.py

import fileinput 

if __name__ == '__main__': 
    for line in fileinput.input(): 
     #do stuff here 
     process_line(line) 
Cuestiones relacionadas