204 lines
14 KiB
HTML
204 lines
14 KiB
HTML
<!DOCTYPE html>
|
||
|
||
<html lang="en" data-content_root="./">
|
||
<head>
|
||
<meta charset="utf-8" />
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||
<title>Using async and await — Flask Documentation (3.2.x)</title>
|
||
<link rel="stylesheet" type="text/css" href="_static/pygments.css?v=6625fa76" />
|
||
<link rel="stylesheet" type="text/css" href="_static/flask.css?v=b87c8d14" />
|
||
<script src="_static/documentation_options.js?v=56528222"></script>
|
||
<script src="_static/doctools.js?v=9bcbadda"></script>
|
||
<script src="_static/sphinx_highlight.js?v=dc90522c"></script>
|
||
<script data-project="flask" data-version="3.2.x" src="_static/describe_version.js?v=fa7f30d0"></script>
|
||
<link rel="icon" href="_static/shortcut-icon.png"/>
|
||
<link rel="index" title="Index" href="genindex.html" />
|
||
<link rel="search" title="Search" href="search.html" />
|
||
<link rel="next" title="API" href="api.html" />
|
||
<link rel="prev" title="Apache httpd" href="deploying/apache-httpd.html" />
|
||
</head><body>
|
||
<div class="related" role="navigation" aria-label="Related">
|
||
<h3>Navigation</h3>
|
||
<ul>
|
||
<li class="right" style="margin-right: 10px">
|
||
<a href="genindex.html" title="General Index"
|
||
accesskey="I">index</a></li>
|
||
<li class="right" >
|
||
<a href="py-modindex.html" title="Python Module Index"
|
||
>modules</a> |</li>
|
||
<li class="right" >
|
||
<a href="api.html" title="API"
|
||
accesskey="N">next</a> |</li>
|
||
<li class="right" >
|
||
<a href="deploying/apache-httpd.html" title="Apache httpd"
|
||
accesskey="P">previous</a> |</li>
|
||
<li class="nav-item nav-item-0"><a href="index.html">Flask Documentation (3.2.x)</a> »</li>
|
||
<li class="nav-item nav-item-this"><a href="">Using <code class="docutils literal notranslate"><span class="pre">async</span></code> and <code class="docutils literal notranslate"><span class="pre">await</span></code></a></li>
|
||
</ul>
|
||
</div>
|
||
|
||
<div class="document">
|
||
<div class="documentwrapper">
|
||
<div class="bodywrapper">
|
||
<div class="body" role="main">
|
||
|
||
<section id="using-async-and-await">
|
||
<span id="async-await"></span><h1>Using <code class="docutils literal notranslate"><span class="pre">async</span></code> and <code class="docutils literal notranslate"><span class="pre">await</span></code><a class="headerlink" href="#using-async-and-await" title="Link to this heading">¶</a></h1>
|
||
<details class="changelog">
|
||
<summary>Changelog</summary><div class="versionadded">
|
||
<p><span class="versionmodified added">Added in version 2.0.</span></p>
|
||
</div>
|
||
</details><p>Routes, error handlers, before request, after request, and teardown
|
||
functions can all be coroutine functions if Flask is installed with the
|
||
<code class="docutils literal notranslate"><span class="pre">async</span></code> extra (<code class="docutils literal notranslate"><span class="pre">pip</span> <span class="pre">install</span> <span class="pre">flask[async]</span></code>). This allows views to be
|
||
defined with <code class="docutils literal notranslate"><span class="pre">async</span> <span class="pre">def</span></code> and use <code class="docutils literal notranslate"><span class="pre">await</span></code>.</p>
|
||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="nd">@app</span><span class="o">.</span><span class="n">route</span><span class="p">(</span><span class="s2">"/get-data"</span><span class="p">)</span>
|
||
<span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">get_data</span><span class="p">():</span>
|
||
<span class="n">data</span> <span class="o">=</span> <span class="k">await</span> <span class="n">async_db_query</span><span class="p">(</span><span class="o">...</span><span class="p">)</span>
|
||
<span class="k">return</span> <span class="n">jsonify</span><span class="p">(</span><span class="n">data</span><span class="p">)</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>Pluggable class-based views also support handlers that are implemented as
|
||
coroutines. This applies to the <a class="reference internal" href="api.html#flask.views.View.dispatch_request" title="flask.views.View.dispatch_request"><code class="xref py py-meth docutils literal notranslate"><span class="pre">dispatch_request()</span></code></a>
|
||
method in views that inherit from the <a class="reference internal" href="api.html#flask.views.View" title="flask.views.View"><code class="xref py py-class docutils literal notranslate"><span class="pre">flask.views.View</span></code></a> class, as
|
||
well as all the HTTP method handlers in views that inherit from the
|
||
<a class="reference internal" href="api.html#flask.views.MethodView" title="flask.views.MethodView"><code class="xref py py-class docutils literal notranslate"><span class="pre">flask.views.MethodView</span></code></a> class.</p>
|
||
<div class="admonition-using-async-with-greenlet admonition">
|
||
<p class="admonition-title">Using <code class="docutils literal notranslate"><span class="pre">async</span></code> with greenlet</p>
|
||
<p>When using gevent or eventlet to serve an application or patch the
|
||
runtime, greenlet>=1.0 is required. When using PyPy, PyPy>=7.3.7 is
|
||
required.</p>
|
||
</div>
|
||
<section id="performance">
|
||
<h2>Performance<a class="headerlink" href="#performance" title="Link to this heading">¶</a></h2>
|
||
<p>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.</p>
|
||
<p>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.</p>
|
||
<p><strong>Async is not inherently faster than sync code.</strong> 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.</p>
|
||
</section>
|
||
<section id="background-tasks">
|
||
<h2>Background tasks<a class="headerlink" href="#background-tasks" title="Link to this heading">¶</a></h2>
|
||
<p>Async functions will run in an event loop until they complete, at
|
||
which stage the event loop will stop. This means any additional
|
||
spawned tasks that haven’t completed when the async function completes
|
||
will be cancelled. Therefore you cannot spawn background tasks, for
|
||
example via <code class="docutils literal notranslate"><span class="pre">asyncio.create_task</span></code>.</p>
|
||
<p>If you wish to use background tasks it is best to use a task queue to
|
||
trigger background work, rather than spawn tasks in a view
|
||
function. With that in mind you can spawn asyncio tasks by serving
|
||
Flask with an ASGI server and utilising the asgiref WsgiToAsgi adapter
|
||
as described in <a class="reference internal" href="deploying/asgi.html"><span class="doc">ASGI</span></a>. This works as the adapter creates
|
||
an event loop that runs continually.</p>
|
||
</section>
|
||
<section id="when-to-use-quart-instead">
|
||
<h2>When to use Quart instead<a class="headerlink" href="#when-to-use-quart-instead" title="Link to this heading">¶</a></h2>
|
||
<p>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 <a class="reference external" href="https://github.com/pallets/quart">Quart</a>. Quart is a reimplementation of
|
||
Flask based on the <a class="reference external" href="https://asgi.readthedocs.io/en/latest/">ASGI</a> standard instead of WSGI. This allows it to
|
||
handle many concurrent requests, long running requests, and websockets
|
||
without requiring multiple worker processes or threads.</p>
|
||
<p>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 <code class="docutils literal notranslate"><span class="pre">async</span></code>/
|
||
<code class="docutils literal notranslate"><span class="pre">await</span></code> 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.</p>
|
||
</section>
|
||
<section id="extensions">
|
||
<h2>Extensions<a class="headerlink" href="#extensions" title="Link to this heading">¶</a></h2>
|
||
<p>Flask extensions predating Flask’s async support do not expect async views.
|
||
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.</p>
|
||
<p>Extension authors can support async functions by utilising the
|
||
<a class="reference internal" href="api.html#flask.Flask.ensure_sync" title="flask.Flask.ensure_sync"><code class="xref py py-meth docutils literal notranslate"><span class="pre">flask.Flask.ensure_sync()</span></code></a> method. For example, if the extension
|
||
provides a view function decorator add <code class="docutils literal notranslate"><span class="pre">ensure_sync</span></code> before calling
|
||
the decorated function,</p>
|
||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="k">def</span><span class="w"> </span><span class="nf">extension</span><span class="p">(</span><span class="n">func</span><span class="p">):</span>
|
||
<span class="nd">@wraps</span><span class="p">(</span><span class="n">func</span><span class="p">)</span>
|
||
<span class="k">def</span><span class="w"> </span><span class="nf">wrapper</span><span class="p">(</span><span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
|
||
<span class="o">...</span> <span class="c1"># Extension logic</span>
|
||
<span class="k">return</span> <span class="n">current_app</span><span class="o">.</span><span class="n">ensure_sync</span><span class="p">(</span><span class="n">func</span><span class="p">)(</span><span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">)</span>
|
||
|
||
<span class="k">return</span> <span class="n">wrapper</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>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.</p>
|
||
</section>
|
||
<section id="other-event-loops">
|
||
<h2>Other event loops<a class="headerlink" href="#other-event-loops" title="Link to this heading">¶</a></h2>
|
||
<p>At the moment Flask only supports <a class="reference external" href="https://docs.python.org/3/library/asyncio.html#module-asyncio" title="(in Python v3.13)"><code class="xref py py-mod docutils literal notranslate"><span class="pre">asyncio</span></code></a>. It’s possible to
|
||
override <a class="reference internal" href="api.html#flask.Flask.ensure_sync" title="flask.Flask.ensure_sync"><code class="xref py py-meth docutils literal notranslate"><span class="pre">flask.Flask.ensure_sync()</span></code></a> to change how async functions
|
||
are wrapped to use a different library.</p>
|
||
</section>
|
||
</section>
|
||
|
||
|
||
<div class="clearer"></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<span id="sidebar-top"></span>
|
||
<div class="sphinxsidebar" role="navigation" aria-label="Main">
|
||
<div class="sphinxsidebarwrapper">
|
||
|
||
|
||
<p class="logo"><a href="index.html">
|
||
<img class="logo" src="_static/flask-vertical.png" alt="Logo of Flask"/>
|
||
</a></p>
|
||
|
||
|
||
<h3>Contents</h3>
|
||
<ul>
|
||
<li><a class="reference internal" href="#">Using <code class="docutils literal notranslate"><span class="pre">async</span></code> and <code class="docutils literal notranslate"><span class="pre">await</span></code></a><ul>
|
||
<li><a class="reference internal" href="#performance">Performance</a></li>
|
||
<li><a class="reference internal" href="#background-tasks">Background tasks</a></li>
|
||
<li><a class="reference internal" href="#when-to-use-quart-instead">When to use Quart instead</a></li>
|
||
<li><a class="reference internal" href="#extensions">Extensions</a></li>
|
||
<li><a class="reference internal" href="#other-event-loops">Other event loops</a></li>
|
||
</ul>
|
||
</li>
|
||
</ul>
|
||
<h3>Navigation</h3>
|
||
<ul>
|
||
<li><a href="index.html">Overview</a>
|
||
<ul>
|
||
<li>Previous: <a href="deploying/apache-httpd.html" title="previous chapter">Apache httpd</a>
|
||
<li>Next: <a href="api.html" title="next chapter">API</a>
|
||
</ul>
|
||
</li>
|
||
</ul>
|
||
<search id="searchbox" style="display: none" role="search">
|
||
<h3 id="searchlabel">Quick search</h3>
|
||
<div class="searchformwrapper">
|
||
<form class="search" action="search.html" method="get">
|
||
<input type="text" name="q" aria-labelledby="searchlabel" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false"/>
|
||
<input type="submit" value="Go" />
|
||
</form>
|
||
</div>
|
||
</search>
|
||
<script>document.getElementById('searchbox').style.display = "block"</script><div id="ethical-ad-placement"></div>
|
||
</div>
|
||
</div>
|
||
<div class="clearer"></div>
|
||
</div>
|
||
<div class="footer" role="contentinfo">
|
||
© Copyright 2010 Pallets.
|
||
Created using <a href="https://www.sphinx-doc.org/">Sphinx</a> 8.1.3.
|
||
</div>
|
||
</body>
|
||
</html>
|