2010-04-14 15 views
18

Używam moduł subprocess na Python 2.5 do tarła program Java (serwer selenu, być precyzyjny) w następujący sposób:Zabijanie podproces tym jego dzieci z pytona

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) 

Proces ten ma na celu zostaną zabici po zakończeniu testów automatycznych. Używam os.kill, aby to zrobić:

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

To nie działa. Powodem jest to, że podproces powłoki tworzy kolejny proces dla java, a pid tego procesu jest nieznany dla mojego kodu Pythona. Próbowałem zabić grupę procesów z os.killpg, ale to zabija również proces python, który uruchamia ten kod w pierwszej kolejności. Ustawienie powłoki na wartość false, co pozwala uniknąć uruchamiania java w środowisku powłoki, również nie wchodzi w grę z innych powodów.

Jak mogę zabić powłokę i inne procesy przez nią wygenerowane?

+0

To tylko wersja unix, prawda? – Macke

+1

related: [Jak zakończyć podprocesor Pythona uruchamiany z powłoką = True] (http://stackoverflow.com/q/4789837/4279) – jfs

Odpowiedz

4

Oczywistym rozwiązaniem w tym przypadku jest może obejmować powłoki:

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) 

To spowoduje, że proces jest procesem Java bezpośrednio. Należy pamiętać, że wciąż może on odradzać procesy, które nie są częścią grupy procesów, więc os.killpg może nadal nie wiedzieć o ich zabiciu.

Jeśli masz powód, aby wywołać powłokę (powyższy kod nie działa, a jest kilka rzeczy, których nie możesz zrobić bez powłoki, ale załóżmy, że tak), musisz sprawić, żeby powłoka przekazała ci pid z proces, który zaczął jakoś. Robienie tego nie jest proste i raczej sytuacyjne.

+2

Lub, jeśli z jakiegokolwiek powodu włączasz powłokę (powiedzmy, że chcesz rozwinąć/podstawienie/cokolwiek), użyj "exec" na początku, aby uniknąć rozwidlenia powłoki. (W szczególności, dodanie "exec" na początku definicji "polecenia" naprawiłoby twój problem.) – moshez

+0

@moshez, niesamowite! to zrobiło. wielkie dzięki. – afroulas

+1

Czy rzeczywiście masz * powód * do włączenia powłoki? Bardzo rzadko jest. –

26

obsłużyć ogólny problem:

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

setsid będzie uruchomić program w nowej sesji, zatem przypisanie nowej grupy procesów do niej i jej dzieci. Wywoływanie na nim kodu os.killpg nie spowoduje również przerwania procesu pisania w Pythonie.

+0

Nie trzeba używać 'setsid'; możesz [wywołać 'os.setsid' w Pythonie] (http://stackoverflow.com/a/4791612/4279) – jfs

+0

Nie, nie możesz ... to zmieni sesję samego procesu, jeśli to, co masz po zabiciu tylko dzieci to nie jest to, co chcesz – berdario

+0

ponownie odczytać tytuł pytania: * "Zabicie podprocesora, w tym jego dzieci z Pythona" * – jfs

Powiązane problemy