2010-04-14 4 views
18

que estoy usando el módulo de subproceso en pitón 2,5 a desovar un programa java (el servidor de selenio, para ser más precisos) como sigue:Killing un subproceso incluyendo sus niños de pitón

import os 
import subprocess 

display = 0 
log_file_path = "/tmp/selenium_log.txt" 
selenium_port = 4455 
selenium_folder_path = "/wherever/selenium/lies" 

env = os.environ 
env["DISPLAY"] = ":%d.0" % display 
command = ["java", 
      "-server", 
      "-jar", 
      'selenium-server.jar', 
      "-port %d" % selenium_port] 
log = open(log_file_path, 'a') 
comm = ' '.join(command) 
selenium_server_process = subprocess.Popen(comm, 
              cwd=selenium_folder_path, 
              stdout=log, 
              stderr=log, 
              env=env, 
              shell=True) 

Este proceso se supone que es ser asesinado una vez que las pruebas automatizadas hayan finalizado. Estoy usando os.kill para hacer esto:

os.killpg(selenium_server_process.pid, signal.SIGTERM) 
selenium_server_process.wait() 

Esto no funciona. La razón es que el subproceso shell genera otro proceso para java, y el pid de ese proceso es desconocido para mi código python. Intenté eliminar el grupo de procesos con os.killpg, pero eso también acaba con el proceso de python que ejecuta este código. Establecer shell en falso, evitando así que java se ejecute dentro de un entorno de shell, también está fuera de cuestión, debido a otras razones.

¿Cómo puedo matar el shell y cualquier otro proceso generado por él?

+0

Esto es solo unix, ¿verdad? – Macke

+1

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

Respuesta

4

La solución obvia en este caso es no implicar la cáscara:

import os 
import subprocess 

display = 0 
log_file_path = "/tmp/selenium_log.txt" 
selenium_port = 4455 
selenium_folder_path = "/wherever/selenium/lies" 

env = os.environ 
env["DISPLAY"] = ":%d.0" % display 
command = ["java", 
      "-server", 
      "-jar", 
      'selenium-server.jar', 
      "-port", 
      str(selenium_port)] 
log = open(log_file_path, 'a') 
selenium_server_process = subprocess.Popen(command, 
              cwd=selenium_folder_path, 
              stdout=log, 
              stderr=subprocess.STDOUT, 
              env=env) 

Esto hará que el proceso sea el proceso de Java directamente. Tenga en cuenta que aún puede generar procesos que no forman parte del grupo de procesos, por lo que os.killpg aún puede no saber cómo matarlos.

Si tiene un motivo para invocar el shell (el código anterior no, y hay algunas cosas que no puede hacer sin el shell, pero suponga que lo hace), tendría que hacer que el shell le pase el pid de el proceso comenzó de alguna manera. Hacer esto no es sencillo, y más bien situacional.

+2

O, si involucra el shell por alguna razón (digamos que desea expansión/sustitución/lo que sea), use "exec" al principio para evitar el bifurcación del shell. (Específicamente, solo agregar "exec" al comienzo de la definición de "comando" hubiera solucionado tu problema.) – moshez

+0

@moshez, ¡increíble! eso lo hizo muchas gracias. – afroulas

+1

¿De verdad tiene una * razón * para involucrar al caparazón? Es muy raro que lo sea –

26

para manejar el problema general:

p=subprocess.Popen(your_command, preexec_fn=os.setsid) 
os.killpg(os.getpgid(p.pid), signal.SIGTERM) 

setsid se ejecute el programa en una nueva sesión, asignando así un nuevo grupo de procesos a ella y sus hijos. llamando al os.killpg en él no reducirá su propio proceso de python también.

+0

No es necesario usar 'setsid'; puedes [llamar a 'os.setsid' en Python] (http://stackoverflow.com/a/4791612/4279) – jfs

+0

No, no puedes ... eso cambiará la sesión del proceso en sí, si lo que eres después está matando solo a los niños no es lo que quiere – berdario

+0

releer el título de la pregunta: * "Eliminar un subproceso incluyendo sus hijos de python" * – jfs

Cuestiones relacionadas