El script de Python canalizado toma el 100% de la CPU cuando se lee de una tubería rota

Tengo dos scripts de Python que se ejecutan en una máquina Ubuntu Linux. El primero envía toda su salida a stdout, el segundo lee desde stdin. Están conectados por una tubería simple, es decir, algo como esto:

./step1.py  | ./step2.py  

Lo que hace step2 es que lee líneas de entrada en un bucle infinito y las procesa:

 while True: try: l = sys.stdin.readline() # processing here 

Step1 se bloquea de vez en cuando. Cuando eso sucede (no estoy seguro de si siempre, pero al menos en varias ocasiones) es que en lugar de estrellarse / detenerse, step2 se vuelve loco y comienza a tomar el 100% de la CPU hasta que la mato manualmente.

¿Por qué sucede esto y cómo puedo hacer que step2 sea más robusto para que se detenga cuando se rompe la tubería?

¡Gracias!

Otros ya explicaron por qué terminas en un bucle sin fin en ciertos casos.

En el segundo guión (lectura), puede usar el idioma:

 for line in sys.stdin: process(line) 

De esta manera no terminarás en un bucle sin fin. Además, en realidad no mostró la excepción que intenta capturar en el segundo script, pero supongo que de vez en cuando experimentará un error de “tubería rota”, que puede y debe detectar como se describe aquí: Cómo manejar un tubo roto (SIGPIPE) en python?

Todo el esquema podría verse así:

 try: for line in sys.stdin: process(line) except IOError, e: if e.errno == errno.EPIPE: # EPIPE error else: # Other error 

Cuando el paso 1 muere, tiene un bucle while con un bash en una statement que generará una excepción. Por lo tanto, continuamente intentará y fallará usando el 100% de la CPU, ya que la línea de lectura no se bloqueará cuando esté lanzando una excepción.

Agregue un retardo de tiempo a la lectura con time.sleep o, mejor aún, preste atención a los errores que lee la línea de lectura y time.sleep el error específico que se produce cuando se detiene el paso 1 y salga del progtwig en lugar de intentar leer desde un canal muerto.

Probablemente desee un operador de reposo cuando la tubería esté vacía y una salida cuando la tubería muera, pero qué excepción se produce con qué mensaje en cada caso, lo dejo como un ejercicio para que usted lo determine. El operador de reposo no es necesario en una situación así, pero evitará otras situaciones en las que pueda alcanzar un uso elevado de la CPU en un trabajo inútil.