문제 발생
파일 핸들 누수가 생기면 수천 개 파일을 처리하다 Too many open files가 발생할 수 있습니다. 정상 경로에서는 close()를 호출하지만 decode 오류나 조기 return 경로에서 파일이 닫히지 않으면 descriptor가 반복마다 남습니다.
file object를 명시적으로 닫지 않고 GC 시점에 기대면 descriptor가 늦게 반환될 수 있어 with context manager를 사용해야 합니다.
원인 분석
Python 객체가 언젠가 수거될 것이라는 기대와 OS 자원이 필요한 시점에 닫힌다는 보장은 다릅니다. 열린 파일 수를 작업 전후와 예외 뒤에 비교하고, 파일을 만든 코드와 닫는 코드가 여러 함수로 흩어져 있는지 확인합니다. with는 context manager의 __exit__를 호출해 block이 정상 종료되거나 예외로 빠져나갈 때 정리 지점을 제공합니다.
해결 방안
파일 수명주기를 사용하는 block에 묶고 encoding을 명시합니다.
from pathlib import Path
def first_line(path: Path) -> str:
with path.open("r", encoding="utf-8") as handle:
return handle.readline().rstrip("\n")
여러 context manager를 동적으로 관리해야 할 때는 contextlib.ExitStack을 검토합니다. 정상 처리, decode 오류와 중간 취소를 반복한 뒤 열린 descriptor 수가 기준선으로 돌아오는지 확인합니다.
공식 문서
현재 Python version과 사용하는 자원이 context manager 계약을 제공하는지 확인합니다.