반응형

출처
https://stackoverflow.com/questions/375427/non-blocking-read-on-a-subprocess-pipe-in-python

python에서 subprocess.PIPE로 non-blocking 읽기

저는 subprocess를 시작하기 위해 을 출력 스트림(표준출력)으로 접속하기 위해 subprocess 모듈을 사용하고 있습니다. 저는 그 출력을 non-blocking으로 읽도록 실행하고 싶습니다. .readline을 non-blocking으로 만들거나 .readline를 실행하기 전에 스트림에 데이터가 있는지 검사하는 방법이 있습니까? 저는 이를 Windows나 Linux에서 최소한의 작업으로 이식하고 싶습니다.
여기는 현재 제가 한 방법입니다. (데이터가 없을 때 .readline는 blocking됩니다.)

p = subprocess.Popen('myprogram.exe', stdout = subprocess.PIPE)
output_str = p.stdout.readline()

29개의 답변 중 1개의 답변만 추려냄

fcntl, select, asyncproc는 이 경우 도움이 되지 않을 것입니다.
운영체제에 관계없이 blocking 없이 스트림을 읽는 신뢰성 있는 방법은 Queue.get_nowait()를 사용하는 것입니다.

import sys
from subprocess import PIPE, Popen
from threading  import Thread

try:
    from queue import Queue, Empty
except ImportError:
    from Queue import Queue, Empty  # python 2.x

ON_POSIX = 'posix' in sys.builtin_module_names

def enqueue_output(out, queue):
    for line in iter(out.readline, b''):
        queue.put(line)
    out.close()

p = Popen(['myprogram.exe'], stdout=PIPE, bufsize=1, close_fds=ON_POSIX)
q = Queue()
t = Thread(target=enqueue_output, args=(p.stdout, q))
t.daemon = True # 쓰레드가 프로그램과 함께 죽습니다.
t.start()

# ... 여기서 다른 것을 합니다

# blocking 없이 한 줄을 읽습니다.
try:  line = q.get_nowait() # or q.get(timeout=.1)
except Empty:
    print('no output yet')
else: # 한 줄을 얻었습니다.
    # ... 그 한 줄로 뭔가를 합니다.
반응형
반응형

출처 : 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))
반응형
반응형

출처 : https://stackoverflow.com/questions/36476841/python-how-to-read-stdout-of-subprocess-in-a-nonblocking-way/36477512

nonblocking 방법으로 subprocess의 출력을 읽는 방법

저는 subprocess를 시작하고 표준 출력을 확인하는 간단한 python script를 작성하려고 합니다.

여기에 코드의 스니펫이 있습니다.

process = subprocess.Popen([path_to_exe, os.path.join(temp_dir,temp_file)], stdout=subprocess.PIPE)
while True:   
    output=process.stdout.readline()
    print "test"

문제는 script가 output=process.stdout.readline()에서 대기하고 subprocess가 끝난 후에만 print "test"를 실행하는 것입니다.

subprocess가 종료되는 것을 기다리지 않고 표준 출력을 읽어 그것을 출력하는 방법이 있을까요?

제가 시작한 subprocess는 제가 소스 코드를 가지고 있지 않은 윈도우즈 바이너리입니다.

비슷한 질문을 몇 개 찾았지만 그 답변은 리눅스에서만 적용할 수 있거나 제가 시작한 subprocess의 소스를 가지고 있을 경우에만 적용할 수 있었습니다.


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

select 모듈을 확인하세요.

import subprocess
import select
import time

x=subprocess.Popen(['/bin/bash','-c',"while true; do sleep 5; echo yes; done"],stdout=subprocess.PIPE)

y=select.poll()
y.register(x.stdout,select.POLLIN)

while True:
  if y.poll(1):
     print x.stdout.readline()
  else:
     print "nothing here"
     time.sleep(1)

편집:

POSIX가 아닌 시스템을 위한 쓰레드 처리된 해결책입니다.

import subprocess
from threading import Thread 
import time

linebuffer=[]
x=subprocess.Popen(['/bin/bash','-c',"while true; do sleep 5; echo yes; done"],stdout=subprocess.PIPE)

def reader(f,buffer):
   while True:
     line=f.readline()
     if line:
        buffer.append(line)
     else:
        break

t=Thread(target=reader,args=(x.stdout,linebuffer))
t.daemon=True
t.start()

while True:
  if linebuffer:
     print linebuffer.pop(0)
  else:
     print "nothing here"
     time.sleep(1)
반응형
반응형

출처 : 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