2010-10-11 18 views
5

Me está costando conseguir lo que quiero del módulo de subproceso python (lo que supone una abstracción unificada/independiente de plataforma, afaik, pero don 'Empezaré con eso :)).subproceso python con shell = Verdadero: redirecciones y subproceso independiente de plataforma que mata

Así que lo simple que estoy buscando es lo siguiente. Quiero

  • Inicio de una aplicación (stdio) externo (posiblemente con subproceso), donde uso redirecciones de estilo concha (como './myapp> stdout_log> stderr_log')
    • Básicamente quiero ejecutar una línea de comandos shell, así que tengo que especificar shell = True para subprocess.Popen() (o bien cambios de dirección en la línea de comandos no funcionarán)
  • que quiere poner en marcha esta línea de comandos de manera asíncrona (por lo tanto, se ejecuta como un subproceso independiente, pero mi proceso de python ess no esperará a su finalización)
  • (Mi proceso principal de python miraría los registros del proceso secundario de vez en cuando para extraer información, pero esto es irrelevante para la pregunta)
  • Si mi proceso padre python decide, debería poder terminar este proceso hijo.

Ahora, mis principales problemas son que

  • básicamente estoy obligado a utilizar shell = True, para conseguir cambios de dirección para trabajar
  • Procesamiento del niño stdout/stderr en el pitón de los padres proceso no es una opción, ya que no pude encontrar la funcionalidad para hacerlo sin esperar (y el proceso padre python debe hacer otras cosas mientras el hijo está ejecutándose)
  • Si uso shell = True continuación subprocess.kill() sólo se pondrá fin a la cáscara, pero no el proceso hijo
  • que había necesidad de un método fiable proceso hijo terminación que funciona en cualquier plataforma (pero por lo menos Linux y Windows)

Espero haber sido lo suficientemente específico. Gracias por todas las sugerencias/consejos de antelación - acabo de pasar un día entero con sub-proceso, y en mi humilde opinión es un dolor lejos de cualquiera de plataforma independiente o simples :((pero tal vez sea sólo yo)

ACTUALIZACIÓN (2010 -10-13):

Si inicia un subproceso (incluso con shell = False), la función subprocess.Popen.kill() solo matará ese subproceso (por lo tanto, si hay algún "nieto") "procesos, no van a ser terminados)

leí sobre el uso del parámetro preexec_fn para establecer el SID en todos los procesos secundarios, pero es sólo UNIX:. timeout a subprocess

+0

Relacionado: [Cómo finalizar un subproceso de python iniciado con shell = True] (http://stackoverflow.com/q/4789837/95735) –

Respuesta

4

La última vez que estuve en una situación similar, descubrí que la solución más fácil (y prácticamente la única) era iniciar un hilo que se encargara del proceso de su hijo. Puede tomar diferentes rutas con este método, ya sea para analizar la canalización del comando de estilo de shell y realizarlas en el código de Python (que dijo que no era una opción debido al bloqueo), lo que al mismo tiempo arreglaría su matando el problemaBásicamente, la encapsulación de subprocesos parece ser el camino a seguir.

Lamentablemente, mi experiencia con subprocess es todo en la plataforma de Windows, que tiene toneladas de sus propias peculiaridades. subprocess tiene un montón de fallas en todos lados, aunque debe hacer un buen trabajo dada la existencia de los módulos popen, popen2 y así sucesivamente que se supone que debe reemplazar.

+0

Sí, podría ir por el camino, ya que no tengo ganas perdiendo más tiempo en este camino ... Gracias por la pista. Si eso te sirve de consuelo, el subproceso en Linux también tiene su propio conjunto de peculiaridades. :( – riviera

2

Yendo a través de sus propios problemas a la vez:

básicamente estoy obligado a utilizar la cáscara = realidad, para ir a trabajar redirecciones

que simplemente no puede utilizar el stdout y stderr parámetros?

out_log = open("stdout_log", "w") 
err_log = open("stderr_log", "w") 
subproc = subprocess.popen(..., stdout=out_log, stderr=err_log, ...) 

Procesamiento del niño stdout/stderr en el proceso de pitón padre no es una opción, ya que no pude encontrar la funcionalidad para hacerlo de una manera no espera (y el proceso de pitón padre debe hacer otra cosas mientras el niño se está ejecutando)

Esto se debe a Windows. En sistemas operativos de tipo Unix, solo utiliza el módulo select. Windows solo puede select en sockets, no en archivos.

Si utilizo shell = True entonces subprocess.kill() sólo terminar la cáscara, pero no el proceso hijo

Porque cuando shell=True la cáscara es el proceso hijo, y los comandos son sus hijos.

que había necesidad de un método de terminación de proceso hijo confiable que funciona en cualquier plataforma (pero por lo menos Linux y Windows)

siquiera existe un método de terminación de proceso hijo fiable para Windows? Lo último que escuché, incluso Task Task's End Task no era 100% confiable. Y en Linux, es posible que no pueda eliminar un proceso que tiene un archivo abierto a través de un controlador bloqueado.

Como dijo Stigma, para el soporte de Windows necesitarás usar subprocesos como proxies. Además, debe intentar ejecutar con shell=False, y si no puede, explique por qué no.

+0

"Porque entonces shell = True el shell es el proceso hijo, y los comandos son sus hijos." - Eso es correcto y estoy al tanto de eso, pero esperaría que el proceso _hierarchy_ termine (o al menos una opción para eso). Si el subproceso se supone que es un módulo independiente de plataforma de "alto nivel", en mi humilde opinión, ese sería el comportamiento esperado. (?) – riviera

3

responder a algunas de las cuestiones:

3

yo también tenía una situación similar hace poco, he creado un subproceso pitón que utiliza shell=True, y necesitaba para matar más tarde . Sin embargo, debido al parámetro shell, el proceso 'real' es un hijo del shell, es decir, un nieto del proceso principal. Matar al caparazón hijo no mata automáticamente al nieto.

En mi alto nivel script en Python:

childProcess = subprocess.Popen('python other.py', shell=True) 

para matar a la concha y el nieto 'trabajo real', que hice esto:

subprocess.call("ps -ef | awk '$3 == \"" + str(childProcess.pid) + "\" {print $2}' | xargs kill -9", shell=True) 
childProcess.kill() 

La primera línea mata a todos los niños de el proceso hijo (basado en ps -ef parentage, la segunda línea mata al niño.

Curiosamente, esto es necesario en Ubuntu, pero no estrictamente necesario en Mac OSX, como o En la Mac, el nieto parece asumir el control del proceso de shell hijo original.