[python] 파이썬에서 백그라운드 프로세스를 시작하는 방법?

쉘 스크립트를 훨씬 더 읽기 쉬운 파이썬 버전으로 이식하려고합니다. 원래 쉘 스크립트는 “&”로 백그라운드에서 여러 프로세스 (유틸리티, 모니터 등)를 시작합니다. 파이썬에서 어떻게 동일한 효과를 얻을 수 있습니까? 파이썬 스크립트가 완료 될 때 이러한 프로세스가 죽지 않기를 바랍니다. 나는 그것이 어떻게 든 데몬의 개념과 관련이 있다고 확신하지만, 이것을 쉽게하는 방법을 찾을 수 없었습니다.



답변

참고 :이 답변은 2009 년에 게시 된 것보다 최신 정보입니다. subprocess이제 다른 답변에 표시된 모듈을 사용하는 것이 문서에서 권장 됩니다.

(하위 프로세스 모듈은 새로운 프로세스를 생성하고 결과를 검색 할 수있는보다 강력한 기능을 제공합니다.이 기능을 사용하는 것보다 해당 모듈을 사용하는 것이 좋습니다.)


프로세스를 백그라운드에서 시작하려면 system()셸 스크립트와 동일한 방식으로 프로세스를 사용 하거나 호출하거나 다음과 같이 할 수 spawn있습니다.

import os
os.spawnl(os.P_DETACH, 'some_long_running_command')

(또는 대안으로 이식성이 낮은 os.P_NOWAIT플래그를 사용해보십시오 ).

여기 에서 설명서를 참조 하십시오 .


답변

jkp 의 솔루션이 작동 하는 동안 최신 방식으로 작업을 수행하고 문서가 권장하는 방식으로 subprocess모듈 을 사용하는 것 입니다. 간단한 명령의 경우에는 동일하지만 복잡한 작업을 수행하려는 경우 더 많은 옵션을 제공합니다.

귀하의 경우에 대한 예 :

import subprocess
subprocess.Popen(["rm","-r","some.file"])

rm -r some.file백그라운드에서 실행 됩니다. .communicate()에서 반환 된 객체 를 호출 Popen하면 완료 될 때까지 차단되므로 백그라운드에서 실행하려면 수행하지 마십시오.

import subprocess
ls_output=subprocess.Popen(["sleep", "30"])
ls_output.communicate()  # Will block for 30 seconds

여기 에서 설명서를 참조 하십시오 .

또한 설명의 요점 : 여기서 사용하는 “배경”은 순전히 쉘 개념입니다. 기술적으로, 의미는 프로세스가 완료되기를 기다리는 동안 차단하지 않고 프로세스를 생성하려고한다는 것입니다. 그러나 여기서는 “배경”을 사용하여 셸 배경과 유사한 동작을 나타냅니다.


답변

“Python에서 외부 명령을 호출하는 방법”에 대한 답변을 원할 것입니다 .

가장 간단한 방법은 os.system다음과 같은 기능 을 사용하는 것입니다.

import os
os.system("some_command &")

기본적으로 system함수에 전달하는 것은 스크립트의 쉘에 전달한 것과 동일하게 실행됩니다.


답변

나는 이것을 여기서 발견 했다 :

Windows (win xp)에서 부모 프로세스는 작업이 완료 될 때까지 완료되지 않습니다 longtask.py. CGI 스크립트에서 원하는 것이 아닙니다. 이 문제는 Python에만 국한된 것은 아니며 PHP 커뮤니티에서는 문제가 동일합니다.

해결책은 DETACHED_PROCESS 프로세스 생성 플래그CreateProcesswin API 의 기본 함수 로 전달 하는 것입니다. pywin32를 설치 한 경우 win32process 모듈에서 플래그를 가져올 수 있습니다. 그렇지 않으면 직접 정의해야합니다.

DETACHED_PROCESS = 0x00000008

pid = subprocess.Popen([sys.executable, "longtask.py"],
                       creationflags=DETACHED_PROCESS).pid


답변

생성 된 하위 프로세스를 Python 프로세스 자체에서 분리하고 Python이 종료 된 후에도 계속 실행되도록 subprocess.Popen()하는 close_fds=True매개 변수 와 함께 사용하십시오 .

https://gist.github.com/yinjimmy/d6ad0742d03d54518e9f

import os, time, sys, subprocess

if len(sys.argv) == 2:
    time.sleep(5)
    print 'track end'
    if sys.platform == 'darwin':
        subprocess.Popen(['say', 'hello'])
else:
    print 'main begin'
    subprocess.Popen(['python', os.path.realpath(__file__), '0'], close_fds=True)
    print 'main end'


답변

대화식 세션을 열고 도움말을 발행하여 다른 스레드를 포크하기 위해 os 모듈 조사를 시작하고 싶을 것입니다. 관련 기능은 포크 및 모든 실행 기능입니다. 시작하는 방법에 대한 아이디어를 얻으려면 포크를 수행하는 함수에 이와 같은 것을 넣으십시오 (함수는 프로그램의 이름과 매개 변수를 포함하는 인수로 목록 또는 튜플 ‘args’를 가져와야합니다. 새 스레드에 대한 stdin, out 및 err 정의) :

try:
    pid = os.fork()
except OSError, e:
    ## some debug output
    sys.exit(1)
if pid == 0:
    ## eventually use os.putenv(..) to set environment variables
    ## os.execv strips of args[0] for the arguments
    os.execv(args[0], args)


답변

캡처 출력 및 백그라운드에서 실행 threading

이 답변 에서 언급했듯이 출력을 캡처 stdout=한 다음 시도 read()하면 프로세스가 차단됩니다.

그러나 이것이 필요한 경우가 있습니다. 예를 들어, 두 포트 사이에서 통신하는 두 개의 프로세스 를 시작 하고 stdout을 로그 파일과 stdout에 저장하려고했습니다.

threading모듈은 우리가 그렇게 할 수 있습니다.

먼저이 질문에서 출력 리디렉션 부분을 단독으로 수행하는 방법을 살펴보십시오 .Python Popen : stdout 및 log 파일에 동시에 쓰기

그때:

main.py

#!/usr/bin/env python3

import os
import subprocess
import sys
import threading

def output_reader(proc, file):
    while True:
        byte = proc.stdout.read(1)
        if byte:
            sys.stdout.buffer.write(byte)
            sys.stdout.flush()
            file.buffer.write(byte)
        else:
            break

with subprocess.Popen(['./sleep.py', '0'], stdout=subprocess.PIPE, stderr=subprocess.PIPE) as proc1, \
     subprocess.Popen(['./sleep.py', '10'], stdout=subprocess.PIPE, stderr=subprocess.PIPE) as proc2, \
     open('log1.log', 'w') as file1, \
     open('log2.log', 'w') as file2:
    t1 = threading.Thread(target=output_reader, args=(proc1, file1))
    t2 = threading.Thread(target=output_reader, args=(proc2, file2))
    t1.start()
    t2.start()
    t1.join()
    t2.join()

sleep.py

#!/usr/bin/env python3

import sys
import time

for i in range(4):
    print(i + int(sys.argv[1]))
    sys.stdout.flush()
    time.sleep(0.5)

실행 후 :

./main.py

stdout은 두 줄마다 다음을 포함하기 위해 0.5 초마다 업데이트됩니다.

0
10
1
11
2
12
3
13

각 로그 파일에는 지정된 프로세스에 대한 해당 로그가 포함됩니다.

고무시키는 : https://eli.thegreenplace.net/2017/interacting-with-a-long-running-child-process-in-python/

Ubuntu 18.04, Python 3.6.7에서 테스트되었습니다.