티스토리 뷰

728x90
반응형

안녕하세요. Teus입니다.

 

이번 포스팅은 Flask 2.0에서 지원되는 Async함수에 대해서 이야기 합니다.

1. Flask 2.0

아마 처음에 Flask의 비동기 함수를 보고

 

Flask에서 비동기함수라니, 뭔 멍멍이같은 소리여😒

 

하실 수 있습니다.

 

하지만, Flask가 2.0으로 버전업이 되면서 Async함수를 쓸 수 있게 되었습니다.
Flask Async Official Docs

 

Using async and await — Flask Documentation (2.3.x)

Using async and await Changelog Routes, error handlers, before request, after request, and teardown functions can all be coroutine functions if Flask is installed with the async extra (pip install flask[async]). This allows views to be defined with async d

flask.palletsprojects.com

 

하지만 Aysnc 함수를 만들 수 있다고 했지 ASGI를 지원한다고 하지 않았습니다.

 

아래 예제를 보겠습니다.

import asyncio
from flask import Flask
import threading

app = Flask(__name__)


async def async_sleep():
    await asyncio.sleep(3)
    return 'zzz'


@app.route("/data")
async def get_data():
    print(threading.current_thread())
    data = await async_sleep()
    return data

@app.route("/data_sync")
def get_data_sync():
    import time
    print(threading.current_thread())
    time.sleep(3)    
    return "zzz"

app.run(
    host="127.0.0.1",
    port = 8888,
    processes = 1,
    threaded = False
)

이제 두개의 process에서 requests를 보내보면, 아래와 같습니다.

image.png

 

werkzeug의 thread와 process를 모두 비활성화 시키고

 

비동기 sleep을 진행한 async routersleep을 진행한 일반 router모두

 

3초가 흐른 뒤, 다음 요청을 처리하는것을 알 수 있습니다.

🤔????

우리가 생각하는 비동기랑은 다르게 동작하는 것을 알 수 있습니다.

Aysnc함수를 사용하면 우리가 생각하기에는
  1. A의 요청이 들어오고, 이 요청을 처리다가 I/O작업을 마주함
  2. A는 I/O작업을 진행하느라 cpu가 놀고있음.
  3. 이때 B의 요청이 들어옴
  4. B의 요청을 처리함
  5. B의 요청이 을 처리하다가 I/O작업을 만나면 A의 요청으로 돌아감

과 같이, 동시에 2개이상의 requests를 다룰 수 있을것을 기대 합니다.

하지만 실제로는
  1. A의 요청이 들어오고, 이 요청을 처리하다가 I/O작업을 마주침
  2. I/O작업동안 A의 다른 작업을 진행함

을 수행한다는 것입니다.

2. Flask의 비동기 함수

flask app은 하나의 worker에 하나의 flask app을 호스팅 해줍니다.

 

이때 flask가 비동기 함수를 만나면 해당 작업을 처리하기 위해서app 내에서 thread를 생성하고

 

여기에서 aysncio이벤트루프를 실행시키는 구조로 되어있습니다.

 

그래서 동기함수를 연속으로 실행할 경우 ThreadID가 같지만

image.png

 

비동기함수를 연속으로 실행할 경우 ThreadID가 다른것을 확인할 수 있습니다.

image.png

3. 그럼 Flask 비동기함수는 어떨때 사용하나요?

Flask의 비동기 함수의 경우, 비동기함수를 사용할때 async/await를 사용할 수 있다는 점이 있습니다.

 

하나의 요청을 처리할 때 I/O Bound가 동반되는 작업을 처리할 때 해당 작업을 비동기로 처리할 수 있다는 점이 장점이라고 할 수 있습니다.

import asyncio
from flask import Flask
import time

app = Flask(__name__)

async def myfetch(url, sess):    
    async with sess.get(url) as resp:         
        return url, resp.status, await resp.text()

@app.route("/data")
async def get_multiple_fetch():
    import aiohttp
    st = time.perf_counter()
    target_url = ['www.naver.com', 'www.google.com', 'www.kakao.com', 'devocean.sk.com']*5
    async with aiohttp.ClientSession() as sess:
        ret = await asyncio.gather(*[myfetch(r"https://"+url, sess) for url in target_url])    
    print(f"async time : {time.perf_counter() - st}")
    return "done"

@app.route("/data_sync")
def get_multiple_fetch_sync():
    import requests
    st = time.perf_counter()
    target_url = ['www.naver.com', 'www.google.com', 'www.kakao.com', 'devocean.sk.com']*5
    target_url = [r"https://"+i for i in target_url]
    ret = []
    with requests.Session() as sess:
        for url in target_url:
            resp = sess.get(r"https://"+url, verify=False)
            ret.append((url, resp.status_code, resp.text))
    print(f"sync time : {time.perf_counter() - st}")
    return "done"

app.run(
    host="127.0.0.1",
    port = 8888,
    processes = 1,
    threaded = False
)

image.png

 

image.png

이처럼 하나의 requests를 처리할 대 다수의 I/O작업이 동반될 경우 활용을 고려해볼 수 있겠습니다.

4. 정말 이게 최선인가요?

Flask공식 홈페이지에서는 Flask Async관련 문서에서 대안을 제시해줍니다.

Flask Async Docs

image.png


Quart = Flask.replace("WSGI", "ASGI")
(넝담😅)

 

공식 홈페이지에서는 Flask대신 Quart를 사용하라고 안내해주고 있습니다.

 

Quart같은 경우 Flask와 동일한 인터페이스를 제공하지만, 대신 내부 구현이 ASGI로 되어있는 웹프래임워크 입니다.

 

기존에 Flask를 사용했고, 비동기 함수는 사용하고 싶으면서 FastAPI는 새롭게 배워야 하는 경우 유용한 선택지 입니다.

 

Flask를 Quart를 바꿔주는 Monkey Patch를 통해서, ASGI기반의 Flask를 사용할 수 있게 됩니다.

import asyncio
#from flask import Flask
from quart import Quart
import time

#app = Flask(__name__)
app = Quart(__name__)
...

이제 2개의 Requests를 보낼경우

 

비동기 router의 경우, 두개의 요청을 동시에 처리하는것을 확인 할 수 있습니다.

image.png

참고문헌 : https://testdriven.io/blog/flask-async/

728x90
반응형
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/11   »
1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
글 보관함