2017-12-16 9 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() 

私は別々のスレッドで1つのブロッキング呼び出しを入れても、それを試してみました。しかし、それでも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のようなフレームワークの1つを調べる必要があります。 – dirn

+0

@dimありがとうございました。私は1つのブロックを別のスレッドに移動しようとしました。 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コルーチンとタスクを実行するためにのみ使用されますが、実行中のFlaskアプリケーション(または一般的なもの)の実行には対応していません。

非同期Webフレームワークを使用する場合は、非同期Webフレームワークを作成する必要があります。例えば、おそらく最も人気のある今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の例です。残念ながら、私はフラスコ/フラスコにバインドされています。アレクサのスキルを尋ねます。私は元の質問を修正し、1つのブロッキングコールを別のスレッドに移動しました。しかしまだ運がない – user24502

+0

@ user24502私は答えを更新しました。 –

2

Flaskから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ではありません。

関連する問題