Run synchronous code#
Synchronous code will block the event loop and degrade the performance of the Quart application it is run in. This is because the synchronous code will block the task it is run in and in addition block the event loop. It is for this reason that synchronous code is best avoided, with asynchronous versions used in preference.
It is likely though that you will need to use a third party library that is synchronous as there is no asynchronous version to use in its place. In this situation it is common to run the synchronous code in a thread pool executor so that it doesn’t block the event loop and hence degrade the performance of the Quart application. This can be a bit tricky to do, so Quart provides some helpers to do so. Firstly any synchronous route will be run in an executor, i.e.
@app.route("/")
def sync():
method = request.method
...
will result in the sync function being run in a thread. Note that you
are still within the Contexts, and hence you can still access
the request
, current_app
and other globals.
The following functionality accepts synchronous functions and will run them in a thread,
Route handlers
Endpoint handlers
Error handlers
Context processors
Before request
Before websocket
Before first request
Before serving
After request
After websocket
After serving
Teardown request
Teardown websocket
Teardown app context
Open session
Make null session
Save session
Context usage#
Whilst you can access the request
and other globals in synchronous
routes you will be unable to await coroutine functions. To work around
this Quart provides run_sync()
which can be
used as so,
@app.route("/")
async def sync_within():
data = await request.get_json()
def sync_processor():
# does something with data
...
result = await run_sync(sync_processor)()
return result
this is similar to utilising the asyncio run_in_executor function,
@app.route("/")
async def sync_within():
data = await request.get_json()
def sync_processor():
# does something with data
...
result = await asyncio.get_running_loop().run_in_executor(
None, sync_processor
)
return result
Note
The run_in_executor function does not copy the current context,
whereas the run_sync method does. It is for this reason that the
latter is recommended. Without the copied context the request
and other globals will not be accessible.