-
|
I am new to fastapi and relatively new to async, so this might be a little basic. I am trying to get calls to an endpoint to run asynchronously with the following code: import asyncio
import time
import uvicorn
import fastapi
print(fastapi.__version__)
app = fastapi.FastAPI()
counter = 5
start_time = time.perf_counter()
@app.get("/")
async def read_root():
global counter
counter -= 1
print('to sleep:', counter, 'at', round(time.perf_counter()-start_time, 3))
await asyncio.sleep(counter)
print('wake up :', counter, 'at', round(time.perf_counter()-start_time, 3))
return {"Hello": f"World {counter}"}
if __name__ == '__main__':
asyncio.run(uvicorn.run(app, host="127.0.0.1", port=8000, loop='asyncio', debug=False))To see the problem, i run this code and open the page in my browser 5 times in quick succession. Because the sleep time decreases with every call, i expect the browser to get the results in a different order and the counter to be printed out of order is well. I have tried a bunch of ways, including creating tasks, but no dice: Spend hours searching and trying to fix this, but no success. Does the endpoint function get scheduled as a task? On: windows 10, python 3.7, fastapi 0.57.0 |
Beta Was this translation helpful? Give feedback.
Replies: 6 comments
-
|
I actually don't know the answer- my instinct is something to do with the GIL and executing the same piece of code more than once at the same time. I can tell you that different endpoints should run at the same time: import asyncio
import time
import uvicorn
import fastapi
app = fastapi.FastAPI()
start_time = time.perf_counter()
counter = 5
@app.get("/")
async def read_root():
global counter
counter -= 1
print('to sleep:', counter, 'at', round(time.perf_counter()-start_time, 3))
await asyncio.sleep(counter)
print('wake up :', counter, 'at', round(time.perf_counter()-start_time, 3))
return {"Hello": f"World {counter}"}
@app.get("/2")
async def read_root_2():
global counter
counter -= 1
print('to sleep:', counter, 'at', round(time.perf_counter()-start_time, 3))
await asyncio.sleep(counter)
print('wake up :', counter, 'at', round(time.perf_counter()-start_time, 3))
return {"Hello": f"World {counter}"}
if __name__ == '__main__':
uvicorn.run(app)will get you something like Maybe someone more experienced than me can give the technical explanation. |
Beta Was this translation helpful? Give feedback.
-
|
It does seem to work when i run uvicorn from command line, but not when i run it in a separate process (using multiprocessing). |
Beta Was this translation helpful? Give feedback.
-
|
Given that uvicorn worked from the command line, I decided to try out hypercorn to see if there was any different behavior. Seems that running that server programmatically works fine, so it must be a limitation of (or bug with) uvicorn. I'd suggest opening an issue there and linking back to this one so we can see what the solution ends up being. Here's the hypercorn code looked like it was working as expected: import asyncio
import time
import fastapi
from hypercorn.config import Config
from hypercorn.asyncio import serve
app = fastapi.FastAPI()
start_time = time.perf_counter()
counter = 5
@app.get("/")
async def read_root():
global counter
counter -= 1
print('to sleep:', counter, 'at', round(time.perf_counter()-start_time, 3))
await asyncio.sleep(counter)
print('wake up :', counter, 'at', round(time.perf_counter()-start_time, 3))
return {"Hello": f"World {counter}"}
if __name__ == '__main__':
asyncio.run(serve(app, Config())) |
Beta Was this translation helpful? Give feedback.
-
|
some webbrowser avoid parralelle request, I think it's your issue try to change the url by adding a querystring one tab with (I learned it from https://www.tornadoweb.org/en/stable/faq.html#my-code-is-asynchronous-why-is-it-not-running-in-parallel-in-two-browser-tabs) |
Beta Was this translation helpful? Give feedback.
-
|
Thanks for the help here everyone! 👏 🙇 If that solves the original problem, then you can close this issue @gemerden ✔️ |
Beta Was this translation helpful? Give feedback.
-
|
Cheers @flapili: that seems to work. Thanks all! Still strange that running from command line would not show the same (browser?) behavior .. |
Beta Was this translation helpful? Give feedback.
some webbrowser avoid parralelle request, I think it's your issue
try to change the url by adding a querystring
one tab with
<ip>:<port>?anything=fooa second
<ip>:<port>?anything=bar(I learned it from https://www.tornadoweb.org/en/stable/faq.html#my-code-is-asynchronous-why-is-it-not-running-in-parallel-in-two-browser-tabs)