Lazy Evaluation, 메모리 사용 및 계산을 최적화하기 위한 기법

Lazy Evaluation, 메모리 사용 및 계산을 최적화하기 위한 기법
Photo by Zhang Kenny / Unsplash

Lazy Evaluation

  • Lazy evaluation은 프로그램 실행 중에 표현식의 평가를 그 값이 실제로 필요할 때까지 미루는 기법
    • 프로그램에서 표현식의 결과가 필요하지 않다면, 해당 표현식의 계산을 미룹니다. 예를 들어, 조건문에서 특정 조건이 거짓으로 평가되어 다른 분기의 결과가 필요하지 않는 경우, 결과가 필요하지 않기 때문에 그 분기의 계산은 수행하지 않음
    • 주로 함수형 언어에서 언급된 개념이지만 Python에서도 사용할 수 있음
  • 한 번 계산된 결과는 저장되어, 같은 계산을 다시 요구할 때 재계산하지 않고 저장된 결과를 사용하여 반복적인 계산은 줄임
  • 메모리 사용을 최적화하고, 계산 시간을 절약하며, 무한 데이터 구조를 다룰 수 있게 해줌
  • Python에서는 기본적으로 엄격한 평가(eager evaluation) 전략을 사용
    • 즉, 표현식이 나타나는 즉시 계산이 이루어집니다.
  • Generator, iterator, 그리고 yield 키워드를 사용하여 Lazy evaluation을 구현할 수 있음
    • 필요할 때마다 값을 생성하므로 메모리 사용량을 크게 줄일 수 있어 큰 데이터셋을 다루거나 계산 비용이 높은 연산을 수행할 때 효율적

예시

Generator 사용 케이스

  • Count_up_to()는 최대값까지 숫자를 하나씩 생성하는 Generator
    • Yield를 이용해서, 다음 숫자가 필요할 때마다 생성
def count_up_to(max):
    count = 1
    while count <= max:
        yield count
        count += 1

counter = count_up_to(5)
for number in counter:
    print(number)

Iterator 사용케이스

  • List, Tuple, Dict 모두 iterable Object로 순회할 때 Iterator가 사용됨
  • Iterator는 iter()로 생성되고, next()를 통해서 다음 Element에 접근이 가능하다.
my_list = [1, 2, 3, 4, 5]
my_iter = iter(my_list)

print(next(my_iter))  # 1
print(next(my_iter))  # 2

Usage

  • 무한 시퀀스 생성: 무한한 자연수 시퀀스나, 피보나치 수열 생성시 메모리 제한 없이 원하는 요소를 구할 수 있음
  • 데이터 파이프라인: 복잡한 데이터 처리 작업을 수행할 때, 각 단계에서 전체 데이터셋을 처리하는 대신 필요한 데이터만 처리하여 다음 단계로 전달할 수 있음
  • 조건부 데이터 처리:데이터셋에서 특정 조건을 만족하는 요소만 필요한 경우, Lazy evaluation을 사용하여 해당 조건을 만족하는 요소가 발견될 때까지만 데이터를 처리할 수 있음

Eager Evaluation vs Lazy Evaluation

  • Lazy Evaluation을 사용할 때
    • 데이터 처리 파이프라인 구축시 데이터의 일부만 필요할 때
      • 무한 데이터 스트림 다룰 때 활용
    • 무한 시퀀스 처리시, 한 번에 모든 데이터를 처리할 필요가 없을 때
    • 성능 최적화가 중요한 상황: 계산 비용이 높거나 메모리 사용량을 최소화해야 하는 경우
  • Eager Evaluation을 사용할 때
    • 디버깅과 같이 프로그램 상태를 쉽게 추적하고 바로 진단해야 할 때
    • 계산 결과를 바로 사용해야 하는 경우요
      • 결과를 바로바로 활용해야 하는 경우
    • 프로그램의 복잡성을 줄이고, 코드의 가독성을 높이고자 할 때