동시성과 free-threaded Python¶
v0.10부터 pylopdf는 GIL이 있는 CPython 3.10–3.14용 플랫폼별 abi3 wheel과
free-threaded CPython 3.14용 cp314-cp314t wheel을 모두 배포합니다. 후자를
import해도 GIL이 다시 활성화되지 않습니다.
지원 계약¶
| 사용 방식 | 지원 |
|---|---|
| GIL이 있는 CPython 3.10–3.14 | abi3-py310 wheel로 지원 |
| free-threaded CPython 3.14t | cp314-cp314t wheel로 지원하며 GIL이 꺼진 상태에서 테스트 |
서로 다른 Document 객체의 동시 작업 |
지원. load, save, render, 추출, merge, 압축의 무거운 작업은 GIL을 해제 |
같은 Document의 동시 호출 또는 편집 |
지원하지 않음. lock으로 직렬화하거나 독립된 Document를 사용 |
한 Document의 Document.render_pages(workers=...) |
지원. 같은 Document 안에서 경계가 정해진 병렬 렌더링 방식 |
Pixmap 동시 읽기 |
지원. Pixmap은 불변 |
Page는 부모 Document를 보는 view이므로 같은 Document 규칙을 따릅니다. 외부의
동시 접근은 PyO3의 런타임 borrow 검사에서 거부될 수 있지만, 이 검사를 동기화 수단으로
사용해서는 안 됩니다.
올바른 경계 선택¶
서로 독립된 파일은 worker마다 독립된 Document를 사용합니다.
from concurrent.futures import ThreadPoolExecutor
import pylopdf
def extract(path: str) -> str:
with pylopdf.open(path) as document:
return document.to_markdown()
with ThreadPoolExecutor() as pool:
results = list(pool.map(extract, paths))
한 Document의 여러 페이지를 처리할 때는 외부 스레드에서 같은 Document를 호출하지
말고 render_pages()를 사용합니다.
render_pages()는 하나의 불변 렌더러 snapshot을 사용하고 요청한 페이지 순서와 중복을
유지하며, 추정 동시 작업 메모리를 약 512 MB로 제한합니다.
Pixmap 버퍼¶
free-threaded wheel은 불변 RGBA8 저장소를 읽기 전용, 1차원, zero-copy buffer로 노출합니다.
Py_buffer는 Python 3.11에서 stable ABI에 포함되었으므로 abi3-py310 wheel에서는
노출할 수 없습니다. 해당 wheel에서는 한 번 복사되는 bytes 값인
pixmap.samples를 사용하세요. 이 방식은 buffer 수명과 불변성 보장을 약화하지
않으면서 Python 3.10 호환성을 유지합니다.