2017-12-16 16 views
5

Ich möchte eine asynchrone Funktion ausführen, immer wenn die Kolbenroute ausgeführt wird. Derzeit wird meine abar-Funktion nie ausgeführt. Kannst du mir sagen warum? Vielen Dank:Python3 Asyncio-Aufruf von Flask Route

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() 

Ich versuchte es auch den einen blockierenden Aufruf in einem separaten Thread zu setzen. Aber es ruft immer noch nicht die Abar-Funktion auf.

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' und' loop.run_forever' blockieren beide. Sie sind wahrscheinlich besser dran mit einem Thread. Wenn Sie _need_ benötigen, um asyncio zu verwenden, sollten Sie in eines der Flask-artigen Frameworks schauen, die darauf aufgebaut sind. – dirn

+0

@dim Vielen Dank. Ich habe versucht, eine Blockierung in einen separaten Thread zu verschieben. S. meine bearbeitete Frage! – user24502

Antwort

3

Für gleichen Grund Sie diesen Druck nicht sehen:

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

loop.run_forever() ist nie bereits seit als @dirn genannt bemerkt app.run auch blockiert wird.

Ausführen von globalen blockierenden Ereignisschleife - ist nur so können Sie asyncio Korotinen und Aufgaben ausführen, aber es ist nicht kompatibel mit blockierenden Flask-App (oder mit einer anderen solchen Sache im Allgemeinen).

Wenn Sie ein asynchrones Webframework verwenden möchten, sollten Sie eines auswählen, das asynchron erstellt wurde. Zum Beispiel, wahrscheinlich populärste ist jetzt 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:

über Ihre try Ereignisschleife in Hintergrund-Thread ausgeführt werden. Ich habe nicht viel geforscht, aber es scheint ein Problem in Bezug auf die Trittsicherheit zu sein: viele asyncio Objekte sind nicht threadsicher. Wenn Sie Ihren Code auf diese Weise ändern, wird es funktionieren:

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

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

Aber auch dies ist eine sehr schlechte Idee. Es ist nicht nur sehr unpraktisch, aber ich denke, es würde nicht viel Sinn machen: Wenn Sie Thread verwenden, um asyncio zu starten, warum nicht just use threads in Flask statt asyncio? Sie werden Flask haben wollen und Parallelisierung.

Wenn ich Sie immer noch nicht überzeugen konnte, zumindest einen Blick auf Flask-aiohttp Projekt werfen. Es ist nah an Flask api und ich denke noch besser, dass was du versuchst zu tun.

+0

Vielen Dank für Ihre Erklärung. Das macht Sinn. Es ist auch ein schönes kleines aiohttp Beispiel. Leider bin ich zu Flasche/Flasche gebunden - frage nach einer Alexa Fähigkeit. Ich habe meine ursprüngliche Frage geändert und einen blockierenden Anruf in einen separaten Thread verschoben. Aber immer noch kein Glück – user24502

+0

@ user24502 ​​Ich aktualisierte die Antwort. –

2

Eine einfachere Lösung für Ihr Problem (in meiner voreingenommenen Ansicht) ist von Flask zu Quart wechseln. Wenn dies der Fall vereinfacht Ihre Snippet,

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) 

Wie in den anderen Antworten stellte die Flasche App Lauf blockiert, und tritt nicht in Wechselwirkung mit einer asyncio Schleife. Auf der anderen Seite ist Quart die Flask API, die auf asyncio basiert, also sollte es funktionieren, wie Sie es erwarten.

Auch als Update ist Flask-Aiohttp nicht mehr maintained.

Verwandte Themen