question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

[QUESTION] Best practice when a single handler calls both async and sync functions

See original GitHub issue

First check

  • I used the GitHub search to find a similar issue and didn’t find it.
  • I searched the FastAPI documentation, with the integrated search.
  • I already searched in Google “How to X in FastAPI” and didn’t find any information.

Description

Consider something like this:

@api.get('/handler')
async def handler():
    ...
    # Slow async function
    await my_async_function()
    ....
    # Slow running sync function
    sync_function()

As written above, it’ll work, but the sync function will block the async event loop. Is there any way to avoid this? If the handler is sync instead, then there’s no async loop with which I can use to run the my_async_function. Is it possible to get the underlying event loop so I can run my own async function within a synchronous handler? I found a related question–is this my best bet or should I just stick with the above? https://github.com/tiangolo/fastapi/issues/825

Issue Analytics

  • State:closed
  • Created 4 years ago
  • Reactions:2
  • Comments:8 (4 by maintainers)

github_iconTop GitHub Comments

32reactions
tiangolocommented, Apr 13, 2020

There’s a utility function for that, run_in_threadpool():

from fastapi.concurrency import run_in_threadpool

@api.get('/handler')
async def handler():
    ...
    # Slow async function
    await my_async_function()
    ....
    # Slow running sync function
    await run_in_threadpool(sync_function)

Sadly it’s still not documented, but you can use it already.

9reactions
mlaradjicommented, Mar 11, 2020

Hi @Toad2186. One possible solution is to run the slow function in its own thread (https://docs.python.org/3/library/asyncio-eventloop.html#executing-code-in-thread-or-process-pools):

import asyncio
from functools import partial

async def run_in_thread(sync_function, *args, **kwargs):
    # Get the loop that's running the handler.
    loop = asyncio.get_running_loop() 
    # run_in_executor expects a callable with no arguments. We can use `partial` or maybe `lambda` for that.
    sync_function_noargs = partial(sync_function, *args, **kwargs)
    return await loop.run_in_executor(None, sync_function_noargs)

@api.get('/handler')
async def handler():
    ...
    # Slow async function
    await my_async_function()
    ....
    # Slow running sync function is now a coroutine
    await run_in_thread(sync_function)

What’s nice about run_in_executor is that it will return the result of the synchronous function, or raise the exception raised by the function. You can do something like:

def slow():
  time.sleep(10)
  raise ValueError

async def main():
  try:
    await run_in_thread(slow)
  except ValueError:
    pass

It can also seamlessly use variables, but care must be taken with non-thread-safe synchronous functions.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Async/Await - Best Practices in Asynchronous Programming
The best practices in this article are more what you'd call “guidelines” than actual rules. There are exceptions to each of these guidelines....
Read more >
How to wrap async function calls into a sync function in Node ...
The problem is such that in the fs module you can see completely separate functions for synchronous and asynchronous access to the file...
Read more >
Best Practices for Using async and await, by Damir Arh
The async and await keywords have been a part of the C# programming language for a long time. Despite that, they still hide...
Read more >
Synchronous vs Asynchronous JavaScript – Call Stack ...
In this article, we will learn all about the synchronous and asynchronous parts of JavaScript. You use both in web programming almost daily....
Read more >
Synchronous and asynchronous requests - Web APIs | MDN
XMLHttpRequest supports both synchronous and asynchronous communications. In general, however, asynchronous requests should be preferred to ...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found