logo
Published on

Lazy Loading 은 무엇인가

Authors

TL;DR

Lazy Loading 은 프로그래밍 언어로 리소스나 데이터를 실행 즉시 불러오는 것이 아닌 필요한 시점에 불러오도록 하는 기법이다. 이 기법을 사용하면 리소스를 선언해도 필요한 시점에만 로드 하거나 초기화 하기 때문에 성능 향상을 기대할 수 있다. 반대말은 Eager Loading 이며 Programming Design Pattern 의 일환이다.

주요 활용처

Lazy loading 이 주로 활용되는 활용처를 알아보자.

  1. 대용량 데이터 처리 : 대용량 데이터를 처리할 때 필요한 데이터만 로드하여 메모리를 절약할 수 있다.
  2. 대용량 이미지, 미디어 처리 : 웹 어플리케이션에서 대용량 이미지 혹은 영상을 썸네일 처리 후 요청이 있을때 본 데이터를 처리한다.
  3. 모듈, 라이브러리 등을 로드: 어플리케이션 시작 시 모든 라이브러리 혹은 모듈을 로드하지 않고 필요할 때 로드한다.

실제 활용 방식

지연된 인스턴스 생성

Python property decorator 을 이용해 lazy loading 을 알아보자.

class Parrot:
    def __init__(self):
        self._voltage = 100000

    @property
    def voltage(self):
        """Get the current voltage."""
        return self._voltage

위와 같은 클래스가 있다. Parrot 클래스를 객체로 불러올 때 voltage method 는 바로 로드될 필요가 업다. 이때 property decorator 를 사용해 필요할 때 사용하게 되는데 이와같이 class 의 구성요소를 lazy loading 방식으로 활용할 수 있다.

parrot_object = Parrot()

# volage 가 필요할 때 voltage property 를 호출
voltage = parrot_object.voltage()

또한 cached_property decorator 를 이용해 더욱 성능향상 이나 빈번한 호출에 대응할 수 있다.

from cached_property import cached_property

class MyClass:
    def __init__(self):
        self._data = None

    @cached_property
    def data(self):
        self._data = ...  
        return self._data

위 예시의 data method 는 복잡한 계산이나 쿼리 등을 수행할 때 결과를 처음 호출 시에만 계산하고 이후에는 캐싱된 값을 활용하게 된다.

동적 로딩

Javascript, Python 등 언어에서는 import, require 등의 구문을 이용해 라이브러리를 필요한 시점에 로드할 수 있다.

username = "orc"

import os
key = os.getenv("key")
user_key = f"{username}-{key}"

스크롤 이벤트 기반 로딩

널리 알려진 무한 스크롤 방식으로 Facebook, Twitter 의 UI 가 유명하다. 페이지 접근 시 모든 피드를 로드하지 않고 일부만 로드한다. 로드한 피드를 모두 조회 했다면 (스크롤을 마지막 까지 내렸다면) 다음 피드 청크를 로드한다.

Django 에서의 gettext, gettext_lazy 활용

Python web framework 인 Django 는 공식적으로 Translation 기능을 제공한다. 본 포스트 작성의 목적인 Django 의 gettext, gettext_lazy 기능 비교를 통해 lazy loading 의 활용 사례를 더 알아보자.

gettext, gettext_lazy 의 차이점

gettext 는 호출 즉시 번역이 이루어 지지만 gettext_lazy 는 실제로 필요한 순간에 번역이 이루어 진다. 참고로 Django 에서는 Global namespace 이용 시 발생 가능한 문제를 피하기 위해 _alias 처리해 import 하기를 권장하고 있다.

  1. 특정 파일에 대한 기본 번역 방법으로 gettext_lazy()를 사용해야 할 때가 있습니다. 글로벌 네임스페이스에서 _()가 없으면 개발자는 어떤 번역 함수가 가장 적절한지를 고민해야 합니다.
  2. 밑줄 문자 (_)는 Python의 대화형 셸과 doctest 테스트에서 '이전 결과'를 나타내는 데 사용됩니다. 전역 _() 함수를 설치하면 이러한 사용 사례와 간섭이 발생할 수 있습니다. gettext()을 명시적으로 _()로 가져오면 이러한 문제를 피할 수 있습니다

우선 일반적인 gettext 는 아래와 같이 사용한다. output 변수가 선언된 순간 번역된 string 이 할당되게 된다. (번역 문구는 django-admin makemessages 명령어를 통해 locale 파일을 생성한 후 번역 문구를 입력하게 된다.)

from django.http import HttpResponse
from django.utils.translation import gettext as _


def my_view(request):
    output = _("Welcome to my site.")
    return HttpResponse(output)

gettext_lazy 를 이용해 lazy translation 을 사용할 수 있다. 해당 function 은 name 에 번역 문구가 아닌 번역 레퍼런스를 주입한다. 이후 필요한 시점에 번역 문구를 주입하게 된다. 대표적으로 Django template 에서 활용될 수 있다.

from django.db import models
from django.utils.translation import gettext_lazy as _


class MyThing(models.Model):
    name = models.CharField(help_text=_("This is the help text"))

Django model 의 Meta 구성요소 중 verbose name 은 gettext_lazy 를 사용하기를 권장하고 있다. 영어와 다른 언어의 복수 구성 방법이 다를 때 사용하는 값인데, 역시 바로 번역할 필요가 없는 요소이다.

from django.db import models
from django.utils.translation import gettext_lazy as _


class MyThing(models.Model):
    name = models.CharField(_("name"), help_text=_("This is the help text"))

    class Meta:
        verbose_name = _("my thing")
        verbose_name_plural = _("my things")