개발/Python

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

MinorMan 2023. 1. 20. 12:56
반응형

<질문>

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


<답변1>

하는 동안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

설명서를 참조하십시오here.

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


<답변2>

메모: 이 답변은 2009년에 게시된 것보다 최신 정보가 아닙니다.subprocess다른 답변에 표시된 모듈이 이제 권장됩니다.in the docs

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

백그라운드에서 프로세스를 시작하려면 다음 중 하나를 사용할 수 있습니다.system()쉘 스크립트와 같은 방식으로 호출하거나 다음을 수행할 수 있습니다.spawn그것:

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

(또는 대안으로 휴대성이 떨어지는os.P_NOWAIT깃발).

참조documentation here.


<답변3>

당신은 아마도 대답을 원할 것입니다"How to call an external command in Python".

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

import os
os.system("some_command &")

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


<답변4>

나는 이것을 찾았다here:

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

해결책은 합격이다DETACHED_PROCESSProcess Creation Flag기본으로CreateProcess승리 API의 기능. pywin32를 설치한 경우 win32process 모듈에서 플래그를 가져올 수 있습니다. 그렇지 않으면 직접 정의해야 합니다.

DETACHED_PROCESS = 0x00000008

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

<답변5>

사용subprocess.Popen()이랑close_fds=True생성된 하위 프로세스가 Python 프로세스 자체에서 분리되고 Python이 종료된 후에도 계속 실행되도록 하는 매개 변수입니다.

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'

<답변6>

출력을 캡처하고 threading 을 사용하여 백그라운드에서 실행

말한 바와 같이on this answer, 다음을 사용하여 출력을 캡처하는 경우stdout=그런 다음read(), 프로세스가 차단됩니다.

그러나 이것이 필요한 경우가 있습니다. 예를 들어 시작하고 싶었습니다.two processes that talk over a port between them, stdout을 로그 파일 및 stdout에 저장합니다.

그만큼threading module그렇게 할 수 있습니다.

먼저 이 질문에서 출력 리디렉션 부분만 수행하는 방법을 살펴보십시오.Python Popen: Write to stdout AND log file simultaneously

그 다음에:

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에서 테스트되었습니다.


<답변7>

대화형 세션을 열고 help(os)를 발행하여) 다른 스레드를 분기하기 위한 os 모듈 조사를 시작하고 싶을 것입니다. 관련 기능은 fork 및 exec 기능입니다. 시작하는 방법에 대한 아이디어를 제공하려면 포크를 수행하는 함수에 다음과 같은 것을 넣으십시오(함수는 프로그램의 이름과 해당 매개 변수를 포함하는 인수로 목록 또는 튜플 '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)

<답변8>

당신이 사용할 수있는

import os
pid = os.fork()
if pid == 0:
    Continue to other code ...

이렇게 하면 Python 프로세스가 백그라운드에서 실행됩니다.


<답변9>

나는 이것을 아직 시도하지 않았지만 .py 파일 대신 .pyw 파일을 사용하면 도움이 될 것입니다. pyw 파일에는 콘솔이 없으므로 이론적으로 백그라운드 프로세스처럼 표시되거나 작동하지 않아야 합니다.

반응형