mirror of https://github.com/pallets/flask.git
update async docs
This commit is contained in:
parent
61fbae8664
commit
dc3e9c0cc3
|
@ -0,0 +1,81 @@
|
|||
.. _async_await:
|
||||
|
||||
Using ``async`` and ``await``
|
||||
=============================
|
||||
|
||||
.. versionadded:: 2.0
|
||||
|
||||
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 def`` and use ``await``.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@app.route("/get-data")
|
||||
async def get_data():
|
||||
data = await async_db_query(...)
|
||||
return jsonify(data)
|
||||
|
||||
|
||||
Performance
|
||||
-----------
|
||||
|
||||
Async functions require an event loop to run. Flask, as a WSGI
|
||||
application, uses one worker to handle one request/response cycle.
|
||||
When a request comes in to an async view, Flask will start an event loop
|
||||
in a thread, run the view function there, then return the result.
|
||||
|
||||
Each request still ties up one worker, even for async views. The upside
|
||||
is that you can run async code within a view, for example to make
|
||||
multiple concurrent database queries, HTTP requests to an external API,
|
||||
etc. However, the number of requests your application can handle at one
|
||||
time will remain the same.
|
||||
|
||||
**Async is not inherently faster than sync code.** Async is beneficial
|
||||
when performing concurrent IO-bound tasks, but will probably not improve
|
||||
CPU-bound tasks. Traditional Flask views will still be appropriate for
|
||||
most use cases, but Flask's async support enables writing and using
|
||||
code that wasn't possible natively before.
|
||||
|
||||
|
||||
When to use Quart instead
|
||||
-------------------------
|
||||
|
||||
Flask's async support is less performant than async-first frameworks due
|
||||
to the way it is implemented. If you have a mainly async codebase it
|
||||
would make sense to consider `Quart`_. Quart is a reimplementation of
|
||||
Flask based on the `ASGI`_ standard instead of WSGI. This allows it to
|
||||
handle many concurrent requests, long running requests, and websockets
|
||||
without requiring individual worker processes or threads.
|
||||
|
||||
It has also already been possible to run Flask with Gevent or Eventlet
|
||||
to get many of the benefits of async request handling. These libraries
|
||||
patch low-level Python functions to accomplish this, whereas ``async``/
|
||||
``await`` and ASGI use standard, modern Python capabilities. Deciding
|
||||
whether you should use Flask, Quart, or something else is ultimately up
|
||||
to understanding the specific needs of your project.
|
||||
|
||||
.. _Quart: https://gitlab.com/pgjones/quart
|
||||
.. _ASGI: https://asgi.readthedocs.io/en/latest/
|
||||
|
||||
|
||||
Extensions
|
||||
----------
|
||||
|
||||
Existing Flask extensions only expect views to be synchronous. If they
|
||||
provide decorators to add functionality to views, those will probably
|
||||
not work with async views because they will not await the function or be
|
||||
awaitable. Other functions they provide will not be awaitable either and
|
||||
will probably be blocking if called within an async view.
|
||||
|
||||
Check the changelog of the extension you want to use to see if they've
|
||||
implemented async support, or make a feature request or PR to them.
|
||||
|
||||
|
||||
Other event loops
|
||||
-----------------
|
||||
|
||||
At the moment Flask only supports :mod:`asyncio`. It's possible to
|
||||
override :meth:`flask.Flask.ensure_sync` to change how async functions
|
||||
are wrapped to use a different library.
|
|
@ -1,46 +0,0 @@
|
|||
.. _async_await:
|
||||
|
||||
Using async and await
|
||||
=====================
|
||||
|
||||
.. versionadded:: 2.0
|
||||
|
||||
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 code
|
||||
such as,
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@app.route("/")
|
||||
async def index():
|
||||
return await ...
|
||||
|
||||
including the usage of any asyncio based libraries.
|
||||
|
||||
|
||||
When to use Quart instead
|
||||
-------------------------
|
||||
|
||||
Flask's ``async/await`` support is less performant than async first
|
||||
frameworks due to the way it is implemented. Therefore if you have a
|
||||
mainly async codebase it would make sense to consider `Quart
|
||||
<https://gitlab.com/pgjones/quart>`_. Quart is a reimplementation of
|
||||
the Flask using ``async/await`` based on the ASGI standard (Flask is
|
||||
based on the WSGI standard).
|
||||
|
||||
|
||||
Decorators
|
||||
----------
|
||||
|
||||
Decorators designed for Flask, such as those in Flask extensions are
|
||||
unlikely to work. This is because the decorator will not await the
|
||||
coroutine function nor will they themselves be awaitable.
|
||||
|
||||
|
||||
Other event loops
|
||||
-----------------
|
||||
|
||||
At the moment Flask only supports asyncio - the
|
||||
:meth:`flask.Flask.ensure_sync` should be overridden to support
|
||||
alternative event loops.
|
|
@ -171,16 +171,23 @@ Also see the :doc:`/becomingbig` section of the documentation for some
|
|||
inspiration for larger applications based on Flask.
|
||||
|
||||
|
||||
Async-await and ASGI support
|
||||
Async/await and ASGI support
|
||||
----------------------------
|
||||
|
||||
Flask supports ``async`` coroutines for view functions, and certain
|
||||
others by executing the coroutine on a seperate thread instead of
|
||||
utilising an event loop on the main thread as an async first (ASGI)
|
||||
frameworks would. This is necessary for Flask to remain backwards
|
||||
compatibility with extensions and code built before ``async`` was
|
||||
introduced into Python. This compromise introduces a performance cost
|
||||
compared with the ASGI frameworks, due to the overhead of the threads.
|
||||
Flask supports ``async`` coroutines for view functions by executing the
|
||||
coroutine on a separate thread instead of using an event loop on the
|
||||
main thread as an async-first (ASGI) framework would. This is necessary
|
||||
for Flask to remain backwards compatible with extensions and code built
|
||||
before ``async`` was introduced into Python. This compromise introduces
|
||||
a performance cost compared with the ASGI frameworks, due to the
|
||||
overhead of the threads.
|
||||
|
||||
Due to how tied to WSGI Flask's code is, it's not clear if it's possible
|
||||
to make the ``Flask`` class support ASGI and WSGI at the same time. Work
|
||||
is currently being done in Werkzeug to work with ASGI, which may
|
||||
eventually enable support in Flask as well.
|
||||
|
||||
See :doc:`/async-await` for more discussion.
|
||||
|
||||
|
||||
What Flask is, What Flask is Not
|
||||
|
|
|
@ -59,7 +59,7 @@ instructions for web development with Flask.
|
|||
patterns/index
|
||||
deploying/index
|
||||
becomingbig
|
||||
async_await
|
||||
async-await
|
||||
|
||||
|
||||
API Reference
|
||||
|
|
|
@ -1520,12 +1520,13 @@ class Flask(Scaffold):
|
|||
return False
|
||||
|
||||
def ensure_sync(self, func):
|
||||
"""Ensure that the returned function is sync and calls the async func.
|
||||
"""Ensure that the function is synchronous for WSGI workers.
|
||||
Plain ``def`` functions are returned as-is. ``async def``
|
||||
functions are wrapped to run and wait for the response.
|
||||
|
||||
Override this method to change how the app runs async views.
|
||||
|
||||
.. versionadded:: 2.0
|
||||
|
||||
Override if you wish to change how asynchronous functions are
|
||||
run.
|
||||
"""
|
||||
if iscoroutinefunction(func):
|
||||
return run_async(func)
|
||||
|
|
|
@ -475,8 +475,8 @@ class Blueprint(Scaffold):
|
|||
"""Ensure the function is synchronous.
|
||||
|
||||
Override if you would like custom async to sync behaviour in
|
||||
this blueprint. Otherwise :meth:`~flask.Flask..ensure_sync` is
|
||||
used.
|
||||
this blueprint. Otherwise the app's
|
||||
:meth:`~flask.Flask.ensure_sync` is used.
|
||||
|
||||
.. versionadded:: 2.0
|
||||
"""
|
||||
|
|
|
@ -742,9 +742,10 @@ def run_async(func):
|
|||
"Install Flask with the 'async' extra in order to use async views."
|
||||
)
|
||||
|
||||
# Check that Werkzeug isn't using its fallback ContextVar class.
|
||||
if ContextVar.__module__ == "werkzeug.local":
|
||||
raise RuntimeError(
|
||||
"async cannot be used with this combination of Python & Greenlet versions"
|
||||
"Async cannot be used with this combination of Python & Greenlet versions."
|
||||
)
|
||||
|
||||
@wraps(func)
|
||||
|
@ -763,9 +764,9 @@ def run_async(func):
|
|||
async def inner(*a, **k):
|
||||
"""This restores the context before awaiting the func.
|
||||
|
||||
This is required as the func must be awaited within the
|
||||
context. Simply calling func (as per the
|
||||
copy_current_xxx_context functions) doesn't work as the
|
||||
This is required as the function must be awaited within the
|
||||
context. Only calling ``func`` (as per the
|
||||
``copy_current_xxx_context`` functions) doesn't work as the
|
||||
with block will close before the coroutine is awaited.
|
||||
"""
|
||||
if ctx is not None:
|
||||
|
|
Loading…
Reference in New Issue