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


295

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



1
안녕하세요 Artem. (1) 더 많은 투표, (2) 2010 년 이후의 새로운 권장 방식 (현재 2015 년) 및 (3) 여기에 리디렉션 된 질문 에 대한 답변도 있으므로 Dan의 답변을 수락 하십시오 . 건배 :-)subprocess.Popen()subprocess.Popen()
올리버

1
@olibre 사실 답은 subprocess.Popen("<command>")적절한 shebang이 이끄는 <command> 파일을 사용해야합니다 . bash 및 python 스크립트를 사용하여 나에게 완벽하게 작동 shell합니다. 내부적 으로 부모 프로세스에서 살아남습니다. stdout부모와 같은 터미널로갑니다. 따라서 이것은 &OP 요청 인 쉘 과 매우 유사 합니다. 그러나 지옥, 모든 질문은 매우 복잡하지만 약간의 테스트로 시간이 지나도 문제가 없었습니다.)
flaschbier

답변:


84

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

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


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

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

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

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


8
참고 : 실행 파일의 전체 경로를 지정해야합니다. 이 함수는 PATH 변수를 사용하지 않으며이를 사용하는 변형은 Windows에서 사용할 수 없습니다.
sorin

36
똑바로 위로 나에게 파이썬 충돌.
파블로

29
os.P_DETACH가 os.P_NOWAIT로 대체되었습니다.
스스로

7
사용 subprocess을 제안하는 사람들 이 프로세스를 분리하는 방법에 대한 힌트 를 줄 수 subprocess있습니까?
rakslice

3
attach.py가 백그라운드에서 some_long_running_prog를 읽거나 쓸 수 있도록 Python 스크립트 (예 : attach.py)를 사용하여 백그라운드 프로세스를 찾고 IO를 리디렉션하려면 어떻게해야합니까?
raof01

376

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

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

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


7
@ Dan : 백그라운드에서 실행되면 프로세스를 어떻게 종료합니까? 나는 그것을 잠시 동안 실행하고 (내가 상호 작용하는 데몬이다) 내가 끝내면 죽인다. 문서는 도움이되지 않습니다 ...
Juan

1
@ Dan하지만 PID를 알아야 할 필요는 없습니까? 활동 모니터 / 작업 관리자는 옵션이 아닙니다 (프로그래밍 방식으로 발생해야 함).
Juan

5
그렇다면 Popen ()의 결과를 stdin에 쓰려면 프로세스를 백그라운드로 강제 실행하는 방법은 무엇입니까?
Michael

2
@JFSebastian : 나는 "현재 프로그램의 실행을 멈추지 않는 독립적 인 프로세스를 어떻게 만들 수 있을까"라고 해석했습니다. 좀 더 명확하게 편집하려면 어떻게 제안 하시겠습니까?
Dan

1
@ Dan : 정답은 : Popen()메인 스레드를 막지 않고 데몬이 필요한 경우 python-daemon패키지 를 보고 잘 정의 된 데몬이 어떻게 작동하는지 이해하십시오. 하위 프로세스의 문서에 대한 링크를 제외하고 "하지만 조심"으로 시작하는 모든 것을 제거하면 대답은 괜찮습니다.
jfs

47

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

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

import os
os.system("some_command &")

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


9
IMHO, 파이썬 스크립트는 일반적으로 크로스 플랫폼으로 작성되며 간단한 크로스 플랫폼 솔루션이 있으면이를 사용하는 것이 좋습니다. 미래에 다른 플랫폼으로 작업 해야하는지 여부를 절대 알 수 없습니다 :) 또는 다른 사람이 스크립트를 자신의 플랫폼으로 마이그레이션하려는 경우.
d9k

7
이 명령은 동 기적입니다 (즉, 항상 시작된 프로세스의 종료를 기다립니다).
tav

@ d9k는 os.system이 이식성이 없습니까?
lucid_dreamer 2018 년

1
@ d9k는 이미 posix-land에서 당신을 포지셔닝하는 백그라운드에서 무언가를 실행하는 선택이 아닌가? Windows에서 무엇을 하시겠습니까? 서비스로 실행 하시겠습니까?
lucid_dreamer 2018 년

특정 폴더에서 명령을 실행해야하는 경우 어떻게 사용할 수 있습니까?
mrRobot

29

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

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

6
프로세스 ID를 유지하는 방법을 보여주는 +1 그리고 누군가 프로세스 ID로 나중에 프로그램을 죽이고 싶다면 : stackoverflow.com/questions/17856928/…
iChux

1
이는 Windows 보인다
Audrius Meskauskas

24

생성 된 하위 프로세스를 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'

1
Windows에서는 분리되지 않지만 creationflags 매개 변수 사용
SmartManoj

3
이 솔루션은 Linux에서 하위 프로세스를 좀비로 남겨 둡니다.
TitanFighter

@TitanFighter SIGCHLD SIG_IGN을 설정하면이를 피할 수 있습니다. stackoverflow.com/questions/16807603/…
sailfish009

@Jimmy에게 감사합니다. 귀하의 답변은 유일한 해결책입니다.
sailfish009

12

대화식 세션을 열고 도움말을 발행하여 다른 스레드를 포크하기 위해 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)

2
os.fork()정말 유용하지만 * nix에서만 사용할 수 있다는 주목할만한 단점이 있습니다.
Evan Fosmark

os.fork의 유일한 문제점은 win32 전용이라는 것입니다.
jkp

이 방법에 대한 자세한 내용 : 데몬에게 파이썬 방법을 만들기
아미르 알리 Akbari

또한 유사한 효과를 도달 할 수있다 threading: stackoverflow.com/a/53751896/895245 내가 Windows에서 그 힘의 일을 생각한다.
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

9

캡처 출력 및 백그라운드에서 실행 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에서 테스트되었습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.