Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

How does a non-async function affect an async route? #454

Answered by catwell
wigging asked this question in Q&A
Discussion options

I have a function (see below) in a Quart app that counts prime numbers.

def count_primes_naive(n: int) -> int:
 """Count number of primes below some number."""
 if n < 2:
 return 0
 count = 0
 for x in range(2, n + 1):
 is_prime = True
 for d in range(2, int(x**0.5) + 1):
 if x % d == 0:
 is_prime = False
 break
 if is_prime:
 count += 1
 return count

I use this function in a route as shown here:

from quart import Quart
from .primes import count_primes_naive
app = Quart(__name__)
@app.get("/count")
async def count():
 n = 1_000_000
 p = count_primes_naive(n)
 return f"p is {p}"

Since the count_primes_naive function is not asynchronous, is the /count route still asynchronous?

You must be logged in to vote

count_primes_naive will be called synchronously and block. You should use run_sync.

Replies: 1 comment 8 replies

Comment options

count_primes_naive will be called synchronously and block. You should use run_sync.

You must be logged in to vote
8 replies
Comment options

The requests are still going to take just as long, async does not make code faster. But when using run_sync, the long blocking function won't stop other requests from being handled in the meantime.

Comment options

Yeah, I understand async will not make the code run faster. But I was expecting the requests/sec to be much higher when using run_sync for this particular example. Is there a better way to test this to show the difference between the two approaches?

Comment options

run_sync is spawning a thread, and threads in Python still contend with the GIL. So since you're running something CPU intensive, you're still blocking to some degree. Use a subprocess executor instead for CPU intensive tasks. Unlike run_sync, the current request context can't be sent to subprocesses, so you'd need to send any arguments you need directly, but that's not relevant to the example given. Alternatively, you can attempt to run with Python's new free threading build, but I'm not sure whether that will work well with Hypercorn and Quart yet.

Comment options

@davidism When you say "executor", are your referring to a ProcessPoolExecutor or ThreadPoolExecutor?

Comment options

Use a subprocess executor instead

process

Answer selected by wigging
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Category
Q&A
Labels
None yet

AltStyle によって変換されたページ (->オリジナル) /