
현대 데이터 엔지니어링 환경에서 파이썬(Python)을 활용해 기가바이트(GB) 혹은 테라바이트(TB) 단위의 데이터를 다루는 것은 일상적인 업무가 되었습니다. 하지만 많은 개발자가 대용량 텍스트 파일이나 로그 데이터를 처리할 때 리스트(List) 형식을 고집하다가 메모리 부족(MemoryError) 현상에 직면합니다. 본 가이드에서는 파이썬의 마법과도 같은 기능인 Generator(제너레이터)와 Yield(이일드)가 어떻게 메모리 효율을 극대화하는지 그 내부 원리를 심층 분석하고, 실무에 즉시 적용 가능한 7가지 고성능 해결 전략을 소개합니다.
1. Generator와 Yield의 내부 작동 원리: 지연 평가(Lazy Evaluation)
일반적인 함수는 `return`을 만나면 결과값을 반환하고 함수의 실행 상태를 완전히 종료합니다. 반면, `yield`를 사용하는 제너레이터 함수는 값을 반환하되, 함수의 상태(로컬 변수, 명령어 포인터 등)를 정지(Suspend)시킨 상태로 메모리에 유지합니다. 다음 데이터가 필요할 때 비로소 멈췄던 지점부터 다시 실행됩니다. 이를 통해 모든 데이터를 메모리에 한꺼번에 올리지 않고 '한 번에 하나씩(One item at a time)' 처리하는 지연 평가(Lazy Evaluation) 시스템을 구축할 수 있습니다.
2. 리스트(List) vs 제너레이터(Generator) 핵심 차이 비교
데이터 처리 방식에 따른 리소스 점유와 성능 특성을 분석한 비교표입니다.
| 비교 항목 | 리스트 (List Comprehension) | 제너레이터 (Generator Expression) |
|---|---|---|
| 메모리 점유 | 모든 요소를 메모리에 할당 (데이터 비례) | 현재 처리할 데이터만 할당 (상수 크기) |
| 생성 속도 | 초기 생성 시 모든 연산 수행 (느림) | 즉시 생성 (매우 빠름) |
| 데이터 접근 | 인덱싱 및 반복 접근 가능 | 한 방향(Next)으로만 순회 가능 (일회성) |
| 연산 방식 | Eager Evaluation (즉시 평가) | Lazy Evaluation (지연 평가) |
| 추천 작업 | 소규모 데이터, 반복 재사용 필요 시 | 대용량 로그 처리, 실시간 스트리밍 |
3. 메모리 효율 극대화를 위한 실무 Python Example (7가지)
대용량 데이터 파이프라인 설계 시 성능 병목을 해결하기 위한 실전 코드입니다.
Example 1: 수 기가바이트 로그 파일 한 줄씩 읽기
파일 전체를 메모리에 올리지 않고 행 단위로 처리하여 메모리 폭발을 방지합니다.
def log_reader(file_path):
with open(file_path, "r", encoding="utf-8") as file:
for line in file:
yield line.strip()
# 실무 적용
for log in log_reader("huge_access_log.txt"):
if "ERROR" in log:
print(f"위험 감지: {log}")
Example 2: 제너레이터 표현식으로 메모리 점유 비교
대량의 숫자 리스트와 제너레이터의 메모리 사용량 차이를 객관적으로 확인합니다.
import sys
# 리스트: 모든 숫자를 메모리에 즉시 할당
list_data = [i for i in range(1000000)]
# 제너레이터: 규칙만 저장하고 필요할 때 생성
gen_data = (i for i in range(1000000))
print(f"리스트 메모리: {sys.getsizeof(list_data)} bytes")
print(f"제너레이터 메모리: {sys.getsizeof(gen_data)} bytes")
Example 3: 대규모 DB 쿼리 결과 청크(Chunk) 처리
수백만 건의 DB 레코드를 처리할 때 메모리 부하를 해결하는 패턴입니다.
def fetch_large_data(cursor, chunk_size=1000):
while True:
rows = cursor.fetchmany(chunk_size)
if not rows:
break
for row in rows:
yield row
# 사용 예시
# for row in fetch_large_data(my_cursor):
# process(row)
Example 4: 무한 수열 생성기 (Infinite Sequence)
메모리 한계 없이 끝없이 이어지는 데이터를 다룰 수 있는 유일한 방법입니다.
def infinite_counter():
n = 1
while True:
yield n
n += 1
counter = infinite_counter()
print(next(counter)) # 1
print(next(counter)) # 2
Example 5: 데이터 파이프라인 연결 (Generator Chaining)
여러 단계의 전처리를 체인처럼 연결하여 중간 결과가 메모리를 점유하지 않도록 합니다.
def get_lines(filename):
for line in open(filename):
yield line
def clean_lines(lines):
for line in lines:
yield line.strip()
def filter_errors(lines):
for line in lines:
if "CRITICAL" in line:
yield line
# 파이프라인 실행 (최종 결과 도출 시까지 메모리 최소 사용)
raw = get_lines("system.log")
clean = clean_lines(raw)
errors = filter_errors(clean)
for e in errors:
save_to_db(e)
Example 6: yield from을 이용한 중첩 제너레이터 최적화
복잡한 트리 구조나 중첩된 리스트를 메모리 효율적으로 평탄화(Flattening)합니다.
def sub_generator(data):
yield from data
def main_generator():
yield from sub_generator([1, 2, 3])
yield from sub_generator([4, 5, 6])
for value in main_generator():
print(value)
Example 7: send() 메서드를 활용한 양방향 제너레이터
단순 데이터 전달을 넘어 외부에서 제너레이터 내부 상태를 제어하는 해결 방법입니다.
def smart_filter():
threshold = 10
while True:
val = yield
if val > threshold:
print(f"기준치 {threshold} 초과: {val}")
# 외부에서 send()를 통해 threshold 변경 가능 (실제 구현 시 로직 확장)
f = smart_filter()
next(f) # 제너레이터 준비
f.send(15)
4. 결론: 왜 지금 제너레이터를 배워야 하는가?
데이터가 자산인 시대에 메모리 관리 능력은 시니어 개발자를 구분하는 척도입니다. 제너레이터는 단순히 '멋진 코드'를 작성하는 도구가 아니라, 서버 비용을 절감하고 서비스 안정성을 담보하는 핵심 기술입니다. I/O Bound 작업과 결합된 비동기 제너레이터(Async Generator)까지 확장한다면, 당신의 파이썬 애플리케이션은 비약적인 성능 향상을 이룰 것입니다.
내용 출처 및 기술 참조
- Python PEP 255: Simple Generators
- Python PEP 380: Syntax for Delegating to a Subgenerator
- Real Python: "How to Use Generators and yield in Python"
- Effective Python (2nd Edition) - Item 30: Consider Generators Instead of Returning Lists
'Artificial Intelligence > 60. Python' 카테고리의 다른 글
| [PYTHON] Cython과 PyPy로 순수 파이썬 루프 성능을 100배 개선하는 방법과 2가지 해결책 차이점 (0) | 2026.04.11 |
|---|---|
| [PYTHON] Memory Leak 방지를 위한 gc 모듈 활용 방법과 참조 횟수 관리의 2가지 핵심 차이 (0) | 2026.04.11 |
| [PYTHON] 전이 학습(Transfer Learning)을 마스터하는 7가지 방법과 실무 해결 전략 (0) | 2026.04.10 |
| [PYTHON] 사전 훈련된 모델(Pre-trained Model) 다운로드 방법 7가지와 호환성 해결 전략 (0) | 2026.04.10 |
| [PYTHON] 텐서(Tensor)와 NumPy 배열의 결정적 차이 3가지와 변환 방법 7가지 (0) | 2026.04.10 |