【问题标题】:asyncio event_loop in a Flask appFlask 应用程序中的 asyncio event_loop
【发布时间】:2018-08-06 06:58:25
【问题描述】:

在 Flask 应用程序中运行异步事件循环的最佳方法是什么?

我的 main.py 看起来像这样:

if __name__ == '__main__':
    try:
        app.run(host='0.0.0.0', port=8000, debug=True)
    except:
        logging.critical('server: CRASHED: Got exception on main handler')
        logging.critical(traceback.format_exc())
        raise

要添加异步任务选项,我需要在运行 app 之前创建一个 event_loop,但即使停止应用运行,后台线程仍然挂起(在调试器中可观察到)

if __name__ == '__main__':
    try:
        app.event_loop = asyncio.get_event_loop()
        app.run(host='0.0.0.0', port=8000, debug=True)
    except:
        logging.critical('server: CRASHED: Got exception on main handler')
        logging.critical(traceback.format_exc())
        raise
    finally:
        app.event_loop.stop()
        app.event_loop.run_until_complete(app.event_loop.shutdown_asyncgens())
        app.event_loop.close()

并使用以下内容创建异步任务:

def future_callback(fut):
    if fut.exception():
        logging.error(fut.exception())

def fire_and_forget(func, *args, **kwargs):
    if callable(func):
        future = app.event_loop.run_in_executor(None, func, *args, **kwargs)
        future.add_done_callback(future_callback)
    else:
        raise TypeError('Task must be a callable')

我能找到的唯一解决方案是在finally 块的末尾添加exit(),但我认为它不是正确的解决方案。

【问题讨论】:

  • 最好不要从 Flask 调用 asyncio 代码,对不起。

标签: python flask python-3.6 python-asyncio event-loop


【解决方案1】:

我最初对整个烧瓶应用程序采用了 1 个 event_loop 的方法,但由于一些不同的原因不喜欢这种方法。

相反,我创建了一个帮助文件 custom_flask_async.py,其中包含 2 个函数,

import asyncio


def get_set_event_loop():
    try:
        return asyncio.get_event_loop()
    except RuntimeError as e:
        if e.args[0].startswith('There is no current event loop'):
            asyncio.set_event_loop(asyncio.new_event_loop())
            return asyncio.get_event_loop()
        raise e


def run_until_complete(tasks):
    return get_set_event_loop().run_until_complete(asyncio.gather(*tasks))

我只检查和get_set event_loop 是否将被使用,并在特定请求中等待。而且因为我使用它的主要方式是使用带有聚集的run_until_complete,所以我也在帮助器中使用它。

我也不确定这是否是最好的方法,或者这种方法有什么缺点,但它绝对适合我的目的。

【讨论】:

  • 使用 Python 3.7 你可以使用 asyncio.run 对吗?这将创建事件循环并在请求级别关闭它
【解决方案2】:

最终我找到的最佳解决方案是将我的 Flask 应用程序托管在 uwsgi 中,这样就可以将 mulesspooler 用于异步任务

https://uwsgi-docs.readthedocs.io/en/latest/Spooler.html

https://uwsgi-docs.readthedocs.io/en/latest/Mules.html

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-02-01
    相关资源
    最近更新 更多