반응형

출처 : https://stackoverflow.com/questions/19447603/how-to-kill-a-python-child-process-created-with-subprocess-check-output-when-t

부모 프로세스가 죽을 때 subprocess.check_output()로 생성된 Python 자식 프로세스를 죽이는 방법?

저는 다음처럼 subprocess.check_output()을 사용하는 자식 프로세스를 생성하는 python script를 리눅스 머신에서 실행하려고 합니다.

subprocess.check_output(["ls", "-l"], stderr=subprocess.STDOUT)

문제는 부모 프로세스가 죽었을 때 조차 자식 프로세스가 실행중이라는 것입니다. 부모 프로세스가 죽었을 때 자식 프로세스도 함께 죽일 수 있는 방법이 있습니까?


5개의 답변 중 2개의 답변

당신의 문제는 subprocess.check_output을 사용하는 것입니다. - 당신은 맞게 작성 했습니다만 check_ouput 인터페이스로는 자식 프로세스의 PID를 얻을 수 없습니다. 대신에 Popen을 사용하세요.

proc = subprocess.Popen(["ls", "-l"], stdout=PIPE, stderr=PIPE)

# 여기에서 자식 프로세스의 PID를 얻을 수 있습니다.
global child_pid
child_pid = proc.pid

# 여기서 자식 프로세스가 완료될 때까지 기다릴 수 있습니다.
(output, error) = proc.communicate()

if error:
    print "error:", error

print "output:", output

종료할 때 자식 프로세스를 죽이는 것을 분명하게 만드세요.

import os
import signal
def kill_child():
    if child_pid is None:
        pass
    else:
        os.kill(child_pid, signal.SIGTERM)

import atexit
atexit.register(kill_child)

당신은 두 개의 방법으로 이를 할 수 있습니다. 그들은 check_output 대신에 Popen을 사용해야 합니다. 첫 번째는 다음처럼 try..finally 를 사용하는 더 간단한 방법입니다.

from contextlib import contextmanager

@contextmanager
def run_and_terminate_process(*args, **kwargs):
try:
    p = subprocess.Popen(*args, **kwargs)
    yield p        
finally:
    p.terminate() # sigterm을 보내고, ...
    p.kill()      # sigkill을 보냅니다.

def main():
    with run_and_terminate_process(args) as running_proc:
        # running_proc.stdout.readline() 처럼 당신의 코드를 여기에 작성합니다.

이는 sigint(키보드 인터럽트)와 sigterm을 잡아내지만, sigkill(-9로 kill 스트립트 실행)을 잡아내지 못합니다.

다른 방법은 좀 더 복잡한데 ctypes의 rctl PR_SET_PDEATHSIG을 사용하는 것입니다. 시스템은 자식에게 시그널을 보낼것이고 부모는 어떤 이유(심지어 sigkill)로든 종료합니다.

import signal
import ctypes
libc = ctypes.CDLL("libc.so.6")
def set_pdeathsig(sig = signal.SIGTERM):
    def callable():
        return libc.prctl(1, sig)
    return callable
p = subprocess.Popen(args, preexec_fn = set_pdeathsig(signal.SIGTERM))
반응형
반응형

출처 : http://stackoverflow.com/questions/1191374/using-module-subprocess-with-timeout

timeout과 함께 'subprocess' 모듈 사용하기

여기에 stdout 데이터를 리턴하는 임의의 명령어를 실행하거나 0이 아닌 종료 코드에서 예외를 발생시키는 파이썬 코드가 있습니다.

proc = subprocess.Popen(
    cmd,
    stderr=subprocess.STDOUT,  # Merge stdout and stderr
    stdout=subprocess.PIPE,
    shell=True)

communicate는 프로세스가 종료하기를 기다리는 데 사용합니다.

stdoutdata, stderrdata = proc.communicate()

subprocess 모듈은 몇 초 이상 실행하고 있는 프로세스를 없애는(kill) timtout 능력을 지원하지 않습니다. 그래서 communicate는 영원히 실행될 수 있습니다.
윈도우즈나 리눅스에서 실행하는 데 파이썬 프로그램에서 timeout을 구현할 수 있는 간단한 방법이 있을까요?


20 개의 답변 중 2개의 답변만 추려냄.

Python 3.3+ 에서

from subprocess import STDOUT, check_output

output = check_output(cmd, stderr=STDOUT, timeout=seconds)

output은 명령어의 표준 출력, 표준 에러 데이터가 합쳐진 것을 포함하는 바이트 문자열입니다.

check_output(check_output)은 proc.communicate() 메소드와는 다르게 문제 텍스트에 지정된 대로 0이 아닌 종료 상태에서 CalledProcessError를 발생시킵니다.

저는 불필요하게 자주 사용되기 때문에 shell=True를 제거하였습니다. cmd에서 실제로 필요한 경우 언제든지 다시 추가할 수 있습니다. shell=True를 추가하면 즉, 자식 프로세스가 자체 하위 항목을 생성하는 경우; check_output()은 시간 초과가 나타내는 것보다 훨씬 늦게 반환 할 수 있습니다. Subprocess timeout 실패를 참조하세요.

타임 아웃 기능은 3.2+ subprocess 모듈의 subprocess32(subprocess32) 백 포트를 통해 Python 2.x에서 사용할 수 있습니다.


유닉스를 사용하신다면,

import signal
  ...
class Alarm(Exception):
    pass

def alarm_handler(signum, frame):
    raise Alarm

signal.signal(signal.SIGALRM, alarm_handler)
signal.alarm(5*60)  # 5분
try:
    stdoutdata, stderrdata = proc.communicate()
    signal.alarm(0)  # 알람을 리셋한다.
except Alarm:
    print "헉, 너무 오래 걸립니다!"
    # 그 밖에 무엇이든
반응형

+ Recent posts