2017-12-16 1 views
5

플라스크 경로가 실행될 때마다 비동기 함수를 실행하려고합니다. 현재 내 abar 함수는 실행되지 않습니다. 왠지 말해줘? 대단히 감사합니다Flask 경로에서 Python3 Asyncio 호출

import asyncio 
from flask import Flask 

async def abar(a): 
    print(a) 

loop = asyncio.get_event_loop() 
app = Flask(__name__) 

@app.route("/") 
def notify(): 
    asyncio.ensure_future(abar("abar"), loop=loop) 
    return "OK" 

if __name__ == "__main__": 
    app.run(debug=False, use_reloader=False) 
    loop.run_forever() 

가 나는 또한 별도의 스레드에서 하나의 차단 호출을 넣어 그것을 시도. 그러나 그것은 아직도 abar 함수를 호출하지 않습니다. 이 인쇄 표시되지 않습니다 같은 이유로

import asyncio 
from threading import Thread 
from flask import Flask 

async def abar(a): 
    print(a) 

app = Flask(__name__) 

def start_worker(loop): 
    asyncio.set_event_loop(loop) 
    try: 
     loop.run_forever() 
    finally: 
     loop.close() 

worker_loop = asyncio.new_event_loop() 
worker = Thread(target=start_worker, args=(worker_loop,)) 

@app.route("/") 
def notify(): 
    asyncio.ensure_future(abar("abar"), loop=worker_loop) 
    return "OK" 

if __name__ == "__main__": 
    worker.start() 
    app.run(debug=False, use_reloader=False) 
+2

'app.run'과'loop.run_forever'는 둘 다 차단됩니다. 아마도 스레드를 사용하는 것이 좋습니다. asyncio를 사용할 필요가 있다면, 그 위에 내장 된 Flask와 같은 프레임 워크 중 하나를 조사해야합니다. – dirn

+0

@dim 고맙습니다. 하나의 차단을 별도의 스레드로 옮기려고했습니다. S. 내 수정 된 질문! – user24502

답변

3

:

if __name__ == "__main__": 
    app.run(debug=False, use_reloader=False) 
    print('Hey!') 
    loop.run_forever() 

loop.run_forever()은 @dirn 이미 app.run도 차단 언급하기 때문에 호출되지 않습니다.

글로벌 차단 이벤트 루프 실행 - asyncio coroutines 및 작업을 실행할 수있는 유일한 방법이지만 실행중인 차단 Flask 앱 (또는 일반적으로 다른 모든 항목) 실행과 호환되지 않습니다.

비동기 웹 프레임 워크를 사용하려는 경우 비동기로 생성 된 프레임 워크를 선택해야합니다. 예를 들어, 아마 가장 인기있는 지금 aiohttp입니다 :

from aiohttp import web 


async def hello(request): 
    return web.Response(text="Hello, world") 


if __name__ == "__main__": 
    app = web.Application() 
    app.router.add_get('/', hello) 
    web.run_app(app) # this runs asyncio event loop inside 

UPD : 백그라운드 스레드에서 이벤트 루프를 실행하도록 시도에 대해

. 나는 많은 것을 조사하지는 않았지만, 어떻게 든 문제는 트레드 안전과 관련이 있습니다 : 많은 asyncio 객체는 스레드로부터 안전하지 않습니다. 이 방법으로 코드를 변경하면 작동합니다.

def _create_task(): 
    asyncio.ensure_future(abar("abar"), loop=worker_loop) 

@app.route("/") 
def notify(): 
    worker_loop.call_soon_threadsafe(_create_task) 
    return "OK" 

다시 말하지만 이것은 매우 나쁜 생각입니다. 그것은 매우 불편할뿐만 아니라별로 의미가 없을 것입니다. asyncio를 시작하기 위해 스레드를 사용한다면 왜 asyncio 대신 just use threads in Flask을 사용하지 않을까요? 당신은 플라스크 당신이 원하는 병렬 처리합니다.

아직 설득하지 못했다면, 적어도 Flask-aiohttp 프로젝트를 살펴보십시오. 그것은 플라스크 API에 가깝고 나는 당신이하려고하는 것을 여전히 더 잘 생각합니다.

+0

설명해 주셔서 대단히 감사합니다. 그건 의미가 있습니다. 또한 그것의 좋은 작은 aiohttp 예제. 불행히도 저는 플라스크/플라스크에 묶여 있습니다. 알렉사 기술을 요청하십시오. 원래 질문을 수정하고 하나의 차단 호출을 별도의 스레드로 옮겼습니다. 하지만 아직 운이 없다 – user24502

+0

@ user24502 ​​나는 대답을 업데이트했다. –

2

내 편견에서 내 문제에 대한 간단한 해결책은 플라스크에서 Quart으로 전환하는 것입니다. 그래서 당신의 조각은,

import asyncio 
from quart import Quart 

async def abar(a): 
    print(a) 

app = Quart(__name__) 

@app.route("/") 
async def notify(): 
    await abar("abar") 
    return "OK" 

if __name__ == "__main__": 
    app.run(debug=False) 

플라스크 응용 프로그램의 실행을 차단하고 다른 답변에서 언급하는 것처럼 간단하게, 그리고 asyncio 루프와 상호 작용하지 않습니다. Quart는 asyncio를 기반으로하는 Flask API이므로 예상대로 작동해야합니다.

업데이트로 Flask-Aiohttp는 더 이상 maintained이 아닙니다.