Async with Gevent

Gevent patches Python’s standard library to run within special async workerscalledgreenlets. Gevent has existed since long before Python’s nativeasyncio was available, and Flask has always worked with it.

Gevent is a reliable way to handle numerous, long lived, concurrent connections,and to achieve similar capabilities to ASGI and asyncio. This works withoutneeding to writeasyncdef orawait anywhere, but relies on gevent andgreenlet’s low level manipulation of the Python interpreter.

Deciding whether you should use gevent with Flask, orQuart, or somethingelse, is ultimately up to understanding the specific needs of your project.

Enabling gevent

You need to apply gevent’s patching as early as possible in your code. Thisenables gevent’s underlying event loop and converts many Python internals to runinside it. Add the following at the top of your project’s module or top__init__.py:

importgevent.monkeygevent.monkey.patch_all()

When deploying in production, useGunicorn oruWSGI with a gevent worker, as described on those pages.

To run concurrent tasks within your own code, such as views, usegevent.spawn():

@app.post("/send")defsend_email():gevent.spawn(email.send,to="example@example.example",text="example")return"Email is being sent."

If you need to accessrequest or other Flask context globals within thespawned function, decorate the function withstream_with_context() orcopy_current_request_context(). Prefer passing the exact data you needwhen spawning the function, rather than using the decorators.

Note

When using gevent, greenlet>=1.0 is required. When using PyPy, PyPy>=7.3.7is required.

Combining withasync/await

Gevent’s patching does not interact well with Flask’s built-in asyncio support.If you want to use Gevent and asyncio in the same app, you’ll need to overrideflask.Flask.async_to_sync() to run async functions inside gevent.

importgevent.monkeygevent.monkey.patch_all()importasynciofromflaskimportFlask,requestloop=asyncio.EventLoop()gevent.spawn(loop.run_forever)classGeventFlask(Flask):defasync_to_sync(self,func):defrun(*args,**kwargs):coro=func(*args,**kwargs)future=asyncio.run_coroutine_threadsafe(coro,loop)returnfuture.result()returnrunapp=GeventFlask(__name__)@app.get("/")asyncdefgreet():awaitasyncio.sleep(1)returnf"Hello,{request.args.get("name","World")}!"

This starts an asyncio event loop in a gevent worker. Async functions arescheduled on that event loop. This may still have limitations, and may need tobe modified further when using other asyncio implementations.

libuv

libuv is another event loop implementation thatgevent supports. There’salso a project calleduvloop that enables libuv in asyncio. If you want touse libuv, use gevent’s support, not uvloop. It may be possible to furthermodify theasync_to_sync code from the previous section to work with uvloop,but that’s not currently known.

To enable gevent’s libuv support, add the following at thevery top of yourcode, beforegevent.monkey.patch_all():

importgeventgevent.config.loop="libuv"importgevent.monkeygevent.monkey.patch_all()