복붙노트

[PYTHON] 파이썬 하위 프로세스 타임 아웃?

PYTHON

파이썬 하위 프로세스 타임 아웃?

Python의 subprocess.Popen 메소드에 대한 시간 초과를 설정하는 인수 또는 옵션이 있습니까?

이 같은:

subprocess.Popen ([ '..'], ..., timeout = 20)?

해결법

  1. ==============================

    1.스레딩 모듈의 Timer 클래스를 살펴 보는 것이 좋습니다. Popen에 대해 시간 제한을 구현하는 데 사용했습니다.

    스레딩 모듈의 Timer 클래스를 살펴 보는 것이 좋습니다. Popen에 대해 시간 제한을 구현하는 데 사용했습니다.

    먼저 콜백을 만듭니다.

        def timeout( p ):
            if p.poll() is None:
                print 'Error: process taking too long to complete--terminating'
                p.kill()
    

    그런 다음 프로세스를 엽니 다.

        proc = Popen( ... )
    

    그런 다음 프로세스를 전달하는 콜백을 호출하는 타이머를 만듭니다.

        t = threading.Timer( 10.0, timeout, [proc] )
        t.start()
        t.join()
    

    프로그램의 다른 곳에서 다음 행을 추가 할 수 있습니다.

        t.cancel()
    

    그렇지 않으면 타이머가 끝날 때까지 python 프로그램이 계속 실행됩니다.

    편집 : 나는 p.poll ()과 p.kill () 호출 사이에서 서브 프로세스 p가 종료 될 수있는 경합 조건이 있다고 권고 받았다. 다음 코드로 해결할 수 있다고 생각합니다.

        import errno
    
        def timeout( p ):
            if p.poll() is None:
                try:
                    p.kill()
                    print 'Error: process taking too long to complete--terminating'
                except OSError as e:
                    if e.errno != errno.ESRCH:
                        raise
    

    하위 프로세스가 이미 정상적으로 종료되었을 때 발생하는 특정 예외를 특별히 처리하기 위해 예외 처리를 정리할 수도 있습니다.

  2. ==============================

    2.subprocess.Popen이 차단되지 않으므로 다음과 같은 작업을 수행 할 수 있습니다.

    subprocess.Popen이 차단되지 않으므로 다음과 같은 작업을 수행 할 수 있습니다.

    import time
    
    p = subprocess.Popen(['...'])
    time.sleep(20)
    if p.poll() is None:
      p.kill()
      print 'timed out'
    else:
      print p.communicate()
    

    그것은 끝내기 위해 항상 최소한 20 초를 기다려야한다는 단점이 있습니다.

  3. ==============================

    3.

    import subprocess, threading
    
    class Command(object):
        def __init__(self, cmd):
            self.cmd = cmd
            self.process = None
    
        def run(self, timeout):
            def target():
                print 'Thread started'
                self.process = subprocess.Popen(self.cmd, shell=True)
                self.process.communicate()
                print 'Thread finished'
    
            thread = threading.Thread(target=target)
            thread.start()
    
            thread.join(timeout)
            if thread.is_alive():
                print 'Terminating process'
                self.process.terminate()
                thread.join()
            print self.process.returncode
    
    command = Command("echo 'Process started'; sleep 2; echo 'Process finished'")
    command.run(timeout=3)
    command.run(timeout=1)
    

    이 출력은 다음과 같아야합니다.

    Thread started
    Process started
    Process finished
    Thread finished
    0
    Thread started
    Process started
    Terminating process
    Thread finished
    -15
    

    첫 번째 실행에서 프로세스가 올바르게 완료되고 (반환 코드 0), 두 번째 프로세스에서 프로세스가 종료되었다는 것을 알 수 있습니다 (반환 코드 -15).

    나는 창문에서 테스트하지 않았다. 하지만, 예제 명령을 업데이트하는 것 외에, thread.join 또는 process.terminate가 지원되지 않는다고 말하는 문서에서 발견되지 않았기 때문에 작동해야한다고 생각합니다.

  4. ==============================

    4.너 할 수있어.

    너 할 수있어.

    from twisted.internet import reactor, protocol, error, defer
    
    class DyingProcessProtocol(protocol.ProcessProtocol):
        def __init__(self, timeout):
            self.timeout = timeout
    
        def connectionMade(self):
            @defer.inlineCallbacks
            def killIfAlive():
                try:
                    yield self.transport.signalProcess('KILL')
                except error.ProcessExitedAlready:
                    pass
    
            d = reactor.callLater(self.timeout, killIfAlive)
    
    reactor.spawnProcess(DyingProcessProtocol(20), ...)
    

    Twisted의 비동기 프로세스 API를 사용합니다.

  5. ==============================

    5.파이썬 하위 프로세스 자동 타임 아웃은 내장되어 있지 않으므로 직접 빌드해야합니다.

    파이썬 하위 프로세스 자동 타임 아웃은 내장되어 있지 않으므로 직접 빌드해야합니다.

    이것은 우분투에서 작동합니다 12.10 python 2.7.3 실행

    이것을 test.py라는 파일에 넣으십시오.

    #!/usr/bin/python
    import subprocess
    import threading
    
    class RunMyCmd(threading.Thread):
        def __init__(self, cmd, timeout):
            threading.Thread.__init__(self)
            self.cmd = cmd 
            self.timeout = timeout
    
        def run(self):
            self.p = subprocess.Popen(self.cmd)
            self.p.wait()
    
        def run_the_process(self):
            self.start()
            self.join(self.timeout)
    
            if self.is_alive():
                self.p.terminate()   #if your process needs a kill -9 to make 
                                     #it go away, use self.p.kill() here instead.
    
                self.join()
    
    RunMyCmd(["sleep", "20"], 3).run_the_process()
    

    저장하고 실행하십시오.

    python test.py
    

    sleep 20 명령을 완료하는 데 20 초가 걸립니다. 3 초 이내에 종료되지 않으면 프로세스가 종료됩니다.

    el@apollo:~$  python test.py 
    el@apollo:~$ 
    

    프로세스가 실행될 때까지 3 초가 소요되며 프로세스가 종료됩니다.

  6. ==============================

    6.불행히도 그러한 해결책은 없습니다. 나는 타임 아웃 후에 그것을 죽일 수있는 프로세스와 함께 시작될 스레드 타이머를 사용하여이 작업을 수행했지만 좀비 프로세스 나 일부 때문에 부적절한 파일 설명자 문제가 발생했습니다.

    불행히도 그러한 해결책은 없습니다. 나는 타임 아웃 후에 그것을 죽일 수있는 프로세스와 함께 시작될 스레드 타이머를 사용하여이 작업을 수행했지만 좀비 프로세스 나 일부 때문에 부적절한 파일 설명자 문제가 발생했습니다.

  7. ==============================

    7.아니오 시간 제한이 없습니다. 내 생각에, 당신이 찾고있는 것은 잠시 후 하위 프로세스를 죽이는 것입니다. 하위 프로세스에 신호를 보낼 수 있기 때문에 하위 프로세스도 죽일 수 있어야합니다.

    아니오 시간 제한이 없습니다. 내 생각에, 당신이 찾고있는 것은 잠시 후 하위 프로세스를 죽이는 것입니다. 하위 프로세스에 신호를 보낼 수 있기 때문에 하위 프로세스도 죽일 수 있어야합니다.

    서브 프로세스에 신호를 보내는 일반적인 접근법 :

    proc = subprocess.Popen([command])
    time.sleep(1)
    print 'signaling child'
    sys.stdout.flush()
    os.kill(proc.pid, signal.SIGUSR1)
    

    이 메커니즘을 사용하여 제한 시간 후에 종료 할 수 있습니다.

  8. ==============================

    8.파이썬 3.3에서, 서브 프로세스 모듈의 블로킹 도우미 함수에 대한 타임 아웃 인수도 있습니다.

    파이썬 3.3에서, 서브 프로세스 모듈의 블로킹 도우미 함수에 대한 타임 아웃 인수도 있습니다.

    https://docs.python.org/3/library/subprocess.html

  9. ==============================

    9.예, https://pypi.python.org/pypi/python-subprocess2는 Popen 모듈을 두 가지 추가 기능으로 확장합니다.

    예, https://pypi.python.org/pypi/python-subprocess2는 Popen 모듈을 두 가지 추가 기능으로 확장합니다.

    Popen.waitUpTo(timeout=seconds)
    

    프로세스가 완료 될 때까지 일정한 시간 (초) 동안 대기하고 그렇지 않으면 반환하지 않습니다.

    또한,

    Popen.waitOrTerminate
    

    이것은 한 지점까지 기다린 다음 .terminate ()를 호출 한 다음 .kill ()을 호출하거나, 둘 중 하나 또는 둘 다 조합하십시오. 자세한 내용은 docs를 참조하십시오.

    http://htmlpreview.github.io/?https://github.com/kata198/python-subprocess2/blob/master/doc/subprocess2.html

  10. ==============================

    10.Linux의 경우 신호를 사용할 수 있습니다. 이것은 플랫폼에 따라 다르므로 Windows에 다른 솔루션이 필요합니다. Mac에서도 작동 할 수 있습니다.

    Linux의 경우 신호를 사용할 수 있습니다. 이것은 플랫폼에 따라 다르므로 Windows에 다른 솔루션이 필요합니다. Mac에서도 작동 할 수 있습니다.

    def launch_cmd(cmd, timeout=0):
        '''Launch an external command
    
        It launchs the program redirecting the program's STDIO
        to a communication pipe, and appends those responses to
        a list.  Waits for the program to exit, then returns the
        ouput lines.
    
        Args:
            cmd: command Line of the external program to launch
            time: time to wait for the command to complete, 0 for indefinitely
        Returns:
            A list of the response lines from the program    
        '''
    
        import subprocess
        import signal
    
        class Alarm(Exception):
            pass
    
        def alarm_handler(signum, frame):
            raise Alarm
    
        lines = []
    
        if not launch_cmd.init:
            launch_cmd.init = True
            signal.signal(signal.SIGALRM, alarm_handler)
    
        p = subprocess.Popen(cmd, stdout=subprocess.PIPE)
        signal.alarm(timeout)  # timeout sec
    
        try:
            for line in p.stdout:
                lines.append(line.rstrip())
            p.wait()
            signal.alarm(0)  # disable alarm
        except:
            print "launch_cmd taking too long!"
            p.kill()
    
        return lines        
    launch_cmd.init = False
    
  11. from https://stackoverflow.com/questions/3733270/python-subprocess-timeout by cc-by-sa and MIT license