비동기 지원으로 Django View 성능 향상
12877 단어 djangoperformanceapipython
Django를 사용하고 다양한 웹 소스의 많은 데이터로 작업하는 사람에게 이것은 큰 문제입니다. 비동기식 보기를 지원한다는 것은 더 깨끗한 코드, 사물에 대해 생각하는 다른 방식, 그리고 가장 중요하게는 애플리케이션의 성능을 극적으로 개선할 수 있는 능력을 의미합니다.
그러나 조금 백업합시다.
"보기"라는 용어가 생소하더라도 걱정하지 마십시오. 이해하기 쉬운 개념입니다.
뷰는 Django 프레임워크에 내장된 애플리케이션의 핵심 구성 요소입니다. 가장 단순하게 보기는 웹 요청을 받아 웹 응답을 생성하는 Python 함수 또는 클래스입니다. Django 3.1 이전에는 뷰가 Python 스레드로 실행되어야 했습니다. 이제 보기는 Python 스레드 없이 비동기 이벤트 루프에서 실행할 수 있습니다. 이는 Python의 asyncio 라이브러리를 Django 보기 내에서 사용할 수 있음을 의미합니다.
documentation에 따르면:
주요 이점은 Python 스레드를 사용하지 않고 수백 개의 연결을 서비스할 수 있는 기능입니다.
Python의 사용을 포함하여 다른 이점도 있습니다asyncio.gather.
4개의 API 호출을 수행하는 뷰가 있다고 가정해 보겠습니다. 최상의 시나리오에서도 각 호출이 1초만 걸린다면 동기적으로 실행되면 총 4초입니다. 이것이 최상의 시나리오입니다.
Pythons concurrent.futures 라이브러리를 사용하여 해당 시간 프레임을 크게 줄이고 전반적인 상황을 개선할 수 있습니다.
이렇게 하면 이전 예제에서 4개의 API 호출을 동시에 수행할 수 있습니다. 즉, ThreadPoolExecutor와 함께 4개의 작업자를 사용하는 경우 뷰가 총 1초 정도 걸릴 수 있습니다. 모든 계정에서 관행은 필요한 시간을 줄이고 통화를 개선합니다.
이는 몇 초가 중요한 세상에서 중요하며 누군가가 애플리케이션이 로드될 때까지 기다리게 하면 좌절감을 유발할 수 있습니다.
실제 사례: Montana의 Yellowstone River 추적
비동기 보기가 어떻게 성능을 향상시키는지 설명하기 위해 United States Geological Survey (USGS)의 통계 데이터를 표시하는 예제 프로젝트를 만들었습니다.
이 프로젝트는 USGS에 6번의 API 호출을 만들어 내 고향인 몬타나 주의 옐로스톤 강에 있는 6개의 액세스 포인트에 대한 데이터를 수집합니다. 이 데이터에는 당시 각 접근 지점에서 이동하는 물의 양(방류율)과 하천 바닥에 대한 물의 표면 높이인 게이지 높이가 포함됩니다.
예제 1: 동기 방식
암호:
def get_river_flow_and_height(site_id):
"""
Synchronous method to get river data from USGS
"""
response = requests.get(f'https://waterservices.usgs.gov/nwis/iv/?format=json&sites={site_id}¶meterCd=00060,00065&siteStatus=all')
data = parse_flow_and_height_from_json(response.json())
return data
def dashboard_v1(request):
"""
Synchronous view that loads data one at a time
"""
start_time = time.time()
river_data = []
for site_id in SITES.keys():
river_data.append((SITES[site_id], get_river_flow_and_height(site_id)))
return render(request, 'rivers/dashboard.html', {
'river_data': river_data,
'version': 'v1',
'load_time': time.time() - start_time,
})
결과:
데이터가 로드되고 거의 4초가 걸립니다. 이 게시물의 목적을 위해 이것이 우리의 기준이 될 것입니다. 우리가 그 상황을 개선할 수 있는지 봅시다.
예 2: 일부 데이터를 동시에 로드하는 동시 보기
def dashboard_v2(request):
"""
Concurrent view that loads some data simultaneously
"""
start_time = time.time()
river_data = []
with concurrent.futures.ThreadPoolExecutor(max_workers=3) as executor:
for site_id, data in zip(SITES.keys(), executor.map(get_river_flow_and_height, SITES.keys())):
river_data.append((SITES[site_id], data))
return render(request, 'rivers/dashboard.html', {
'river_data': river_data,
'version': 'v2',
'load_time': time.time() - start_time,
})
결과:
이제 약 1.5초로 줄어들었고 이는 크게 개선된 것입니다. 비동기 뷰를 활용할 때 어떤 일이 발생하는지 살펴보겠습니다.
예제 3: 비동기 방식
async def get_river_flow_and_height_async(site_id):
"""
Asynchronous method to get river data from USGS
"""
async with httpx.AsyncClient() as client:
response = await client.get(f'https://waterservices.usgs.gov/nwis/iv/?format=json&sites={site_id}¶meterCd=00060,00065&siteStatus=all')
data = parse_flow_and_height_from_json(response.json())
return data
async def dashboard_v3(request):
"""
Asynchronous view that loads data using asyncio
"""
start_time = time.time()
river_data = []
datas = await asyncio.gather(*[get_river_flow_and_height_async(site_id) for site_id in SITES.keys()])
for site_id, data in zip(SITES.keys(), datas):
river_data.append((SITES[site_id], data))
return render(request, 'rivers/dashboard.html', {
'river_data': river_data,
'version': 'v3',
'load_time': time.time() - start_time,
})
결과:
와, 1초도 안 되어 결과가 나왔습니다. 이는 원래 방법에서 약 3초 개선된 것입니다.
이 예는 비동기식 보기를 활용하여 성능을 크게 향상시키는 방법을 매우 명확하게 보여줍니다.
GitLab에서 전체 프로젝트 보기: https://gitlab.com/nextlink/example-django-async-rivers
이 게시물은 원래 blog at NextLink Labs에 게재되었으며 무엇보다도 devops consulting에 대해 작성했습니다.
Reference
이 문제에 관하여(비동기 지원으로 Django View 성능 향상), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/kjpctech/improving-django-view-performance-with-async-support-52lp텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)