HOWTO · Python
Python에서 스크립트를 다시 시작하는 방법
Python 스크립트를 다시 시작하거나 다시 실행하는 세 가지 방법을 알아보세요. os.execv()로 그 프로세스를 교체하는 방법, subprocess.call()로 자식 프로세스를 시작하는 방법, 루프로 애플리케이션 로직을 반복하는 방법입니다.
이 페이지의 내용
Python 스크립트를 다시 시작하려면 새 인터프리터 프로세스가 필요한지, 아니면 프로그램의 작업만 반복하면 되는지를 선택하세요. os.execv()는 현재 프로세스를 교체하고, subprocess.call()은 자식 프로세스를 시작해 기다리며, 루프는 Python을 다시 시작하지 않고 애플리케이션 로직을 다시 실행할 수 있습니다.
방법 1: os.execv()로 현재 프로세스 교체하기
현재 인터프리터를 같은 스크립트의 새 실행으로 교체해야 할 때 os.execv()를 사용합니다. 실행 파일로 활성 인터프리터를, 인자로 스크립트의 인수 목록을 전달하세요.
os.execv(sys.executable, [sys.executable, *sys.argv])
os와 sys를 가져온 다음, 다시 시작 조건이 충족될 때 이 표현식을 호출합니다. sys.argv에는 스크립트 경로와 스크립트에 전달된 인수가 포함되므로 새 인터프리터가 이를 다시 받습니다. execv()가 성공하면 이전 Python 코드로 돌아오지 않습니다. 운영 체제는 같은 프로세스 슬롯에서 교체 프로그램을 실행합니다. 프로세스를 교체하기 전에 보존해야 할 출력은 모두 플러시하세요. 이 작업은 플랫폼에 따라 다르며 여기서는 실행된 예제로 표시하지 않습니다.
방법 2: subprocess.call()로 새 프로세스 시작하기
현재 프로세스가 부모로 남는 동안 별도의 인터프리터가 스크립트를 실행해야 할 때 subprocess.call()을 사용합니다. 호출은 subprocess.call([sys.executable, *sys.argv])입니다. 먼저 subprocess와 sys를 가져오세요. 이 함수는 자식 프로세스가 끝날 때까지 기다린 다음 자식의 종료 상태를 부모에게 반환합니다. 부모는 자동으로 사라지지 않으므로, 부모가 멈춰야 한다면 호출 후 다시 시작 분기에서 반환하거나 종료하세요. 자식 프로세스가 같은 다시 시작 로직을 상속할 수 있으므로, 그 조건이 결국 실행이 끝나도록 해야 합니다. 이 프로세스 시작 동작은 여기서는 실행된 출력으로 표시하지 않습니다.
방법 3: 루프로 프로그램 로직 반복하기
애플리케이션의 작업만 다시 실행하면 된다면, 그 작업을 함수에 넣고 제어되는 루프에서 호출하세요. 이렇게 하면 같은 인터프리터를 유지하고 자식 프로세스의 체인을 만들지 않을 수 있습니다. 이 예제는 두 번의 실행과 깔끔한 종료를 보여주기 위해 고정된 선택 순서를 사용합니다. 이 순서를 자신의 입력이나 애플리케이션 조건으로 바꾸세요.
이 예제를 실행하세요.
def run_task(number):
print(f"Run {number}")
for number, action in enumerate(("restart", "restart", "exit"), start=1):
if action == "exit":
print("Done")
break
run_task(number)
Run 1
Run 2
Done
실제 명령줄 프로그램에서는 각 반복마다 작업을 읽고, 사용자가 반복을 요청할 때만 run_task()를 호출하세요. 루프에 명확한 종료 조건을 지정하세요. 함수를 반복해도 모듈 전역 변수, 열린 리소스, 인터프리터 상태는 초기화되지 않습니다. 다음 실행에서 다시 사용하면 안 되는 것은 닫거나 다시 초기화하세요.
적절한 다시 시작 방법 선택하기
일회성 스크립트 프로세스를 교체할 때는 os.execv()를, 부모가 별도의 실행을 기다려야 할 때는 subprocess.call()을, 선택한 애플리케이션 작업을 반복하고 싶을 때는 루프를 사용하세요. 이 방법들은 프로세스 수명 주기가 서로 다릅니다. 교체하면 다시 시작할 이전 Python 프레임이 남지 않고, 자식 실행은 기다리는 동안 부모를 유지하며, 루프는 현재 인터프리터 상태를 유지합니다. 웹 서비스의 경우 요청 핸들러에서 워커를 다시 시작하지 말고, 해당 프로세스 관리자나 배포 제어를 사용하세요. 요청 중 다시 시작하면 사용자를 방해하고 메모리에 있는 상태를 잃을 수 있습니다.
자주 묻는 질문
어떤 방법을 선택해야 하나요?
애플리케이션 작업을 반복하려면 루프를, 현재 프로세스를 교체하려면 os.execv()를, 부모 프로세스가 새 인터프리터 실행을 기다려야 한다면 subprocess.call()을 선택하세요.
스크립트가 자동으로 다시 시작할 수 있나요?
예. 구성 변경과 같은 조건이 사용자에게 묻지 않고 다시 시작을 선택할 수 있습니다. 그 조건이 거짓이 되거나 다른 방식으로 다시 시작 주기가 끝나도록 하세요.
다시 시작하면 성능에 영향을 주나요?
인터프리터를 시작하는 데는 시작 비용이 들고, 다시 시작이 잦으면 초기화 작업이 반복될 수 있습니다. 루프는 이러한 프로세스 시작을 피하지만 현재 인터프리터 상태를 유지하므로 명시적인 정리가 필요할 수 있습니다.
다시 시작할 때 변경된 인수를 전달할 수 있나요?
예. sys.argv를 그대로 재사용하지 말고 os.execv()나 subprocess.call()을 위한 새 인수 목록을 만드세요. 인터프리터 실행 파일을 첫 번째 항목으로 유지하고, 애플리케이션 인수 앞에 스크립트 경로를 포함하세요.
웹 애플리케이션이 요청에서 스크립트를 다시 시작해야 하나요?
일반적으로는 아닙니다. 요청 중 워커를 다시 시작하면 서비스가 중단되고 메모리에 있는 상태가 버려질 수 있습니다. 서버나 프로세스 관리자가 지원하는 다시 시작 및 배포 메커니즘을 사용하세요.