반응형
Python의 프로세스 종류와 동작 및 시작 방식
Python의 multiprocessing 모듈은 프로세스를 생성하고 관리하기 위한 강력한 도구를 제공합니다. 이 글에서는 Python의 프로세스 종류와 동작 방식을 이해하고, 시작 방식에 대해서 정리했습니다.
시작 방식 | 특징 | 지원 플랫폼 | 사용 사례 |
spawn | 새로운 Python 인터프리터 프로세스 생성 | Windows, macOS, Unix | 안전성 요구 작업 |
fork | 부모 프로세스를 복제 | Unix 계열 | 속도와 효율성 중시 작업 |
forkserver | 별도의 포크 서버를 통해 프로세스 생성 | Unix 계열 | fork보다 안전성 높은 작업 |
1. 프로세스 종류
Python에서는 두 가지 주요 프로세스 유형이 있습니다:
- 메인 프로세스 (Main Process):
- Python 스크립트를 실행하면 기본적으로 메인 프로세스가 생성됩니다.
- 모든 서브프로세스의 부모 역할을 하며, 프로그램의 진입점입니다.
- 서브프로세스 (Subprocess):
- 메인 프로세스에서 생성된 프로세스로, 작업을 병렬로 수행합니다.
- 독립적인 메모리 공간을 가지며, 다른 서브프로세스와 직접적으로 공유되지 않습니다.
2. 프로세스 동작 방식
- 독립적인 메모리 공간:
- 각 프로세스는 독립적인 메모리 공간을 가지며, 데이터는 기본적으로 공유되지 않습니다.
- 데이터 공유가 필요하면 Queue, Pipe, Value 또는 Array 같은 도구를 사용합니다.
- GIL(Global Interpreter Lock) 우회:
- 멀티스레딩은 GIL의 제약을 받지만, 멀티프로세싱은 각 프로세스가 별도의 Python 인터프리터를 실행하므로 GIL의 영향을 받지 않습니다.
- 병렬 실행:
- 멀티코어 CPU를 활용하여 여러 프로세스가 병렬로 작업을 수행합니다.
3. 프로세스 시작 방식
Python의 multiprocessing 모듈은 운영 체제에 따라 다음 세 가지 프로세스 시작 방식을 지원합니다:
- spawn (생성):
- 새로운 Python 인터프리터 프로세스를 생성합니다.
- 부모 프로세스의 상태는 복제되지 않으며, 필요한 객체는 직렬화(피클링)를 통해 전달됩니다.
- Windows 및 macOS의 기본 방식.
- 특징:
- 더 안전하지만 속도가 느림.
- 데이터 직렬화가 필요.
- fork (복제):
- 부모 프로세스를 그대로 복제하여 새로운 프로세스를 생성합니다.
- Unix 계열에서 기본 방식.
- 특징:
- 빠르고 메모리 효율적.
- 부모 프로세스의 모든 자원을 복제하므로, 스레드 안전 문제가 발생할 수 있음.
- forkserver:
- 별도의 포크 서버 프로세스를 시작하여 새로운 프로세스를 생성합니다.
- 특징:
- fork의 장점(속도와 효율성)을 유지하면서 더 안전함.
- Unix 계열에서만 사용 가능.
반응형
4. 단계별 설명 및 예제 코드
단계 1: 기본 프로세스 생성 (spawn 방식)
import multiprocessing
import os
def worker_function(name):
print(f"Worker {name} is running in process {os.getpid()}")
if __name__ == "__main__":
multiprocessing.set_start_method("spawn") # spawn 방식 설정
print(f"Main process ID: {os.getpid()}")
# 서브프로세스 생성
process1 = multiprocessing.Process(target=worker_function, args=("A",))
process2 = multiprocessing.Process(target=worker_function, args=("B",))
process1.start()
process2.start()
process1.join()
process2.join()
print("Main process finished")
출력 예시:
Main process ID: 12345
Worker A is running in process 12346
Worker B is running in process 12347
Main process finished
단계 2: fork 방식 (Unix 계열에서만)
import multiprocessing
import os
def worker_function(name):
print(f"Worker {name} is running in process {os.getpid()}")
if __name__ == "__main__":
multiprocessing.set_start_method("fork") # fork 방식 설정
print(f"Main process ID: {os.getpid()}")
process = multiprocessing.Process(target=worker_function, args=("Task",))
process.start()
process.join()
print("Main process finished")
출력 예시 (Unix 계열에서만 실행 가능):
Main process ID: 12345
Worker Task is running in process 12346
Main process finished
단계 3: forkserver 방식
import multiprocessing
import os
def worker_function(name):
print(f"Worker {name} is running in process {os.getpid()}")
if __name__ == "__main__":
multiprocessing.set_start_method("forkserver") # forkserver 방식 설정
print(f"Main process ID: {os.getpid()}")
process = multiprocessing.Process(target=worker_function, args=("Task",))
process.start()
process.join()
print("Main process finished")
출력 예시:
Main process ID: 12345
Worker Task is running in process 12346
Main process finished
단계 4: 프로세스 간 통신
Queue를 사용하여 프로세스 간 데이터를 교환하는 예제입니다.
import multiprocessing
def worker(queue):
queue.put("Data from worker")
if __name__ == "__main__":
multiprocessing.set_start_method("spawn") # spawn 방식 설정
queue = multiprocessing.Queue()
process = multiprocessing.Process(target=worker, args=(queue,))
process.start()
process.join()
# Queue에서 데이터 읽기
print(f"Received from worker: {queue.get()}")
출력 예시:
Received from worker: Data from worker
반응형