본문 중간의 쿠팡 추천 상품 구매시 쿠팡 파트너스에서 일정액의 수수료를 제공받습니다.

Python 3.14부터 concurrent.futures.InterpreterPoolExecutor로 같은 프로세스 안에서 여러 인터프리터를 작업자처럼 사용할 수 있습니다. 기존 ThreadPoolExecutor와 같은 Executor 인터페이스를 쓰지만, 각 작업자는 별도의 인터프리터와 별도의 GIL을 갖습니다.
핵심은 CPU 바운드 작업에서 스레드보다 병렬 실행 여지가 커진다는 점입니다. 다만 인터프리터 사이의 상태는 격리되어 있고, 작업 함수와 인자 및 반환값은 직렬화 경계를 지나야 하므로 기존 스레드 풀을 그대로 바꾸는 용도로 보면 안 됩니다.
InterpreterPoolExecutor는 무엇이 다른가
Python 공식 문서 기준으로 InterpreterPoolExecutor는 ThreadPoolExecutor의 하위 클래스입니다. 각 작업자는 스레드 하나에서 실행되지만, 그 스레드 안에서 자기만의 인터프리터를 사용합니다.
일반 스레드 풀은 같은 인터프리터 상태를 공유합니다. 반면 인터프리터 풀의 작업자는 서로 독립된 런타임 상태를 가집니다. 한 인터프리터에서 모듈을 import하거나 sys.stdout을 바꿔도 다른 인터프리터에 자동으로 반영되지 않습니다.

이 격리 덕분에 각 인터프리터는 자기 GIL을 갖습니다. 공식 문서는 이 구조가 여러 CPU 코어에서 Python 코드를 병렬로 실행할 수 있게 한다고 설명합니다.
작업과 데이터는 어떻게 오가나
submit()과 map()의 사용 방식은 다른 executor와 비슷합니다. 차이는 경계입니다. 작업자는 호출할 함수와 인자를 pickle로 직렬화해서 자기 인터프리터로 받고, 반환값도 다시 직렬화해서 돌려줍니다.
from concurrent.futures import InterpreterPoolExecutor
def square(n):
return n * n
with InterpreterPoolExecutor(max_workers=4) as executor:
results = list(executor.map(square, range(10)))
print(results)
따라서 넘기는 함수, 인자, 반환값은 직렬화 가능해야 합니다. 람다, 로컬 함수, 열린 파일 객체처럼 pickle과 맞지 않는 값을 자연스럽게 공유하는 구조로 설계하면 실패하거나 유지보수가 어려워질 수 있습니다.

가변 객체를 여러 작업자가 동시에 공유한다는 기대도 버려야 합니다. 인터프리터 격리는 공유 상태를 줄여 추론을 쉽게 만들 수 있지만, 필요한 데이터 전달은 명시적으로 설계해야 합니다.
ThreadPoolExecutor, ProcessPoolExecutor와 어떻게 고르나
세 executor는 같은 Executor 계열이지만 기본 선택 기준이 다릅니다.
| 도구 | 잘 맞는 작업 | 주의할 점 |
|---|---|---|
ThreadPoolExecutor |
네트워크, 파일 I/O처럼 대기 시간이 큰 작업 | 일반 Python CPU 작업은 같은 인터프리터의 GIL 영향을 받습니다. |
InterpreterPoolExecutor |
같은 프로세스 안에서 격리된 인터프리터로 나눌 수 있는 CPU 작업 | 작업과 데이터가 pickle 경계를 지나며, mutable 객체 공유를 전제로 하면 안 됩니다. |
ProcessPoolExecutor |
프로세스 단위 격리가 필요한 CPU 작업 | __main__ import 가능성, 프로세스 시작 방식, 프로세스 간 직렬화 비용을 고려해야 합니다. |

이미 ThreadPoolExecutor로 충분한 I/O 중심 작업이라면 인터프리터 풀로 바꿀 이유가 크지 않습니다. 반대로 Python 코드 자체가 CPU를 오래 쓰고, 입력과 출력이 직렬화하기 쉬운 값이라면 검토할 만합니다.
실무에서 먼저 확인할 기준
- Python 3.14 이상에서 실행되는 코드인지 확인합니다.
InterpreterPoolExecutor는 Python 3.14에 추가됐습니다. - 작업 함수와 인자, 반환값이 pickle로 전달 가능한지 확인합니다.
- 전역 변수, import 상태, 표준 출력 변경 같은 런타임 상태를 공유한다고 가정하지 않습니다.
- C 확장 모듈을 많이 쓰는 작업은 다중 인터프리터 호환성을 따로 확인합니다.
Executor.map()의chunksize는ThreadPoolExecutor와InterpreterPoolExecutor에서는 효과가 없다는 점을 기억합니다.
FAQ
InterpreterPoolExecutor는 GIL을 없애는 기능인가
아닙니다. 각 인터프리터가 자기 GIL을 갖는 구조입니다. 같은 인터프리터 안의 실행 모델이 사라지는 것이 아니라, 여러 인터프리터가 서로 다른 CPU 코어에서 병렬로 실행될 수 있는 구조입니다.
ThreadPoolExecutor 코드를 그대로 바꿔도 되나
단순한 함수와 직렬화 가능한 데이터만 주고받는 코드라면 바꾸기 쉽습니다. 하지만 공유 전역 상태, mutable 객체 공유, 로컬 함수 전달에 기대는 코드는 먼저 구조를 정리해야 합니다.
ProcessPoolExecutor보다 항상 가벼운가
공식 문서는 여러 인터프리터가 같은 프로세스 안에 머무르므로 프로세스 방식보다 시스템 자원을 덜 쓸 수 있다고 설명합니다. 다만 시작 비용, 메모리 사용량, 확장 모듈 호환성 같은 현재 한계도 있으므로 실제 선택은 작업 특성과 실행 환경을 기준으로 봐야 합니다.
'프로그래밍 > C, C++, Java, Python' 카테고리의 다른 글
| Java Compact Object Headers 기준 (0) | 2026.08.13 |
|---|---|
| Python t-string 사용법 (0) | 2026.08.09 |
| Python Path.info 사용법 (1) | 2026.08.01 |
| Python annotationlib 사용법 (0) | 2026.07.26 |
| Python copy.replace 사용법 (0) | 2026.07.23 |





