
"파이썬 대용량 파일처리 노하우"
데이터 엔지니어링이나 백엔드 개발을 하다 보면, 로컬 메모리(RAM) 용량을 훌쩍 넘어서는 거대한 데이터 파일을 처리해야 할 때가 반드시 옵니다. 무심코 read()나 readlines()를 호출했다가 MemoryError를 만나거나, 서버가 먹통이 되는 경험은 누구나 한 번쯤 겪어보셨을 겁니다.
오늘은 파이썬에서 메모리를 효율적으로 관리하며 대용량 파일을 우아하게 처리하는 노하우 5가지를 정리해 드립니다.
1. 한 번에 읽지 말고 '스트리밍' 하라 (Lazy Evaluation)
가장 기초적이지만 중요한 원칙입니다. 파일 전체를 리스트로 메모리에 올리는 것은 자살행위와 같습니다. 파이썬의 파일 객체는 그 자체로 이터레이터(Iterator)입니다.
😢 나쁜 예 (전체 로드)
# 10GB 파일을 리스트로 다 불러오면 메모리가 터집니다.
with open('huge_data.csv', 'r') as f:
lines = f.readlines() # 위험!
for line in lines:
process(line)
😊좋은 예 (한 줄씩 처리)
# 제너레이터(Generator) 방식으로 한 줄씩 메모리에 올립니다.
with open('huge_data.csv', 'r') as f:
for line in f: # 파일 객체를 직접 순회
process(line)
이 방식은 파일 크기가 100GB라도 메모리 사용량은 한 줄을 처리하는 만큼만 유지됩니다.
2. Pandas를 쓴다면 chunksize를 활용하라
데이터 분석에 필수적인 Pandas는 기본적으로 데이터를 모두 메모리에 올리는 In-Memory 방식입니다. 하지만 chunksize 파라미터를 사용하면 데이터를 일정 단위(청크)로 나누어 로드할 수 있습니다.
import pandas as pd
chunk_size = 100000 # 한 번에 10만 줄씩 읽기
csv_file = 'huge_data.csv'
# chunk는 DataFrame 객체입니다.
for chunk in pd.read_csv(csv_file, chunksize=chunk_size):
# 청크 단위로 필터링하거나 연산 수행
filtered_chunk = chunk[chunk['value'] > 50]
# 결과를 DB에 넣거나 다른 파일로 append 모드로 저장
filtered_chunk.to_csv('processed_data.csv', mode='a', header=False)
이 방식을 사용하면 8GB 램을 가진 노트북에서도 수십 GB의 CSV 파일을 가공할 수 있습니다.
3. 병렬 처리가 필요하다면 Dask를 고려하라
단순히 메모리 문제를 넘어, 처리 속도까지 높이고 싶다면 Dask가 훌륭한 대안입니다. Dask는 Pandas와 문법이 거의 유사하지만, 내부적으로 작업을 작은 단위로 쪼개고 병렬로 처리합니다.
import dask.dataframe as dd
# Pandas와 문법이 매우 유사합니다.
# 실제로는 데이터를 읽지 않고 계산 그래프만 생성합니다 (Lazy).
df = dd.read_csv('huge_data_*.csv')
# 실제 연산은 compute()를 호출할 때 수행됩니다.
result = df.groupby('category').value.mean().compute()
Dask는 가상 메모리를 활용하고 CPU 코어를 모두 사용하여, 단일 코어만 사용하는 Pandas보다 훨씬 빠른 처리가 가능합니다.
4. 바이너리 데이터와 랜덤 액세스에는 mmap
텍스트 파일이 아닌 바이너리 파일을 다루거나, 파일의 특정 위치로 자주 이동해야 한다면 mmap (Memory Mapped File)이 강력한 도구입니다. 운영체제의 가상 메모리 기능을 이용해 파일을 마치 메모리 상의 바이트 배열처럼 다룰 수 있게 해줍니다.
import mmap
with open('huge_binary.bin', 'r+b') as f:
# 파일을 메모리에 매핑 (전체를 로드하지 않음)
with mmap.mmap(f.fileno(), 0) as mm:
# 인덱싱으로 접근 가능
print(mm[:10])
# 특정 위치 찾기 (Seek)
loc = mm.find(b'pattern')
if loc != -1:
mm.seek(loc)
print(mm.read(5))
mmap은 파일 I/O 시스템 콜을 줄여주어 성능 향상에도 큰 도움이 됩니다.
5. 파일 포맷만 바꿔도 절반은 성공: Parquet
CSV는 범용적이지만, 대용량 처리에는 비효율적입니다(타입 추론 비용, 압축 미지원 등). 가능하다면 데이터를 Apache Parquet 형식으로 변환하세요.
- 압축률: CSV 대비 용량이 획기적으로 줄어듭니다.
- 속도: 필요한 컬럼만 읽을 수 있어(Columnar Storage) I/O 속도가 매우 빠릅니다.
- 타입 보존: CSV처럼 매번 데이터 타입을 추론할 필요가 없습니다.
# CSV를 Parquet로 변환 후 저장
df.to_parquet('data.parquet', engine='pyarrow', compression='gzip')
# 필요한 컬럼만 빠르게 로드
df = pd.read_parquet('data.parquet', columns=['id', 'value'])
마치며 (요약)
대용량 파일을 다루는 것은 '얼마나 좋은 장비(RAM)를 쓰느냐'의 문제가 아니라 '데이터를 어떻게 흐르게 (Streaming) 하느냐'의 문제입니다.
- 기본적인 for line in file 루프를 생활화하세요.
- Pandas는 chunksize로 쪼개서 드세요.
- 더 큰 스케일은 Dask나 Spark 같은 분산 처리 프레임워크를 검토하세요.
- CSV 고집을 버리고 Parquet 같은 효율적인 포맷을 도입하세요.
이 원칙들만 지켜도 여러분의 파이썬 코드는 훨씬 더 가볍고 견고해질 것입니다.
'IT > Python' 카테고리의 다른 글
| 파이썬 표준 라이브러리로 '자동 만료(TTL) 딕셔너리' 만들기 (0) | 2025.12.09 |
|---|---|
| 서버 파일을 브라우저로 3초 만에 확인하는 방법 (Python 한 줄 명령어) (0) | 2025.12.09 |
| json.load 와 json.loads 의 차이는 무엇일까요? (0) | 2025.12.06 |
| 파이썬 버전별 비교 및 신규 기능 (0) | 2024.04.09 |
| Python 오류 메시지의 가독성을 높이자! pretty_errors (0) | 2024.04.01 |
댓글