- Published on
Lazy Loading 은 무엇인가
- Authors
- Name
- Orc Hwang
- @orchwang
TL;DR
Lazy Loading
은 프로그래밍 언어로 리소스나 데이터를 실행 즉시 불러오는 것이 아닌 필요한 시점에 불러오도록 하는 기법이다. 이 기법을 사용하면 리소스를 선언해도 필요한 시점에만 로드 하거나 초기화 하기 때문에 성능 향상을 기대할 수 있다. 반대말은 Eager Loading
이며 Programming Design Pattern 의 일환이다.
주요 활용처
Lazy loading 이 주로 활용되는 활용처를 알아보자.
- 대용량 데이터 처리 : 대용량 데이터를 처리할 때 필요한 데이터만 로드하여 메모리를 절약할 수 있다.
- 대용량 이미지, 미디어 처리 : 웹 어플리케이션에서 대용량 이미지 혹은 영상을 썸네일 처리 후 요청이 있을때 본 데이터를 처리한다.
- 모듈, 라이브러리 등을 로드: 어플리케이션 시작 시 모든 라이브러리 혹은 모듈을 로드하지 않고 필요할 때 로드한다.
실제 활용 방식
지연된 인스턴스 생성
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 하기를 권장하고 있다.
- 특정 파일에 대한 기본 번역 방법으로 gettext_lazy()를 사용해야 할 때가 있습니다. 글로벌 네임스페이스에서 _()가 없으면 개발자는 어떤 번역 함수가 가장 적절한지를 고민해야 합니다.
- 밑줄 문자 (_)는 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")