Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Will run_in_executor ever block?

suppose if I have a web server like this:

from fastapi import FastAPI
import uvicorn
import asyncio

app = FastAPI()

def blocking_function():
    import time
    time.sleep(5)
    return 42

@app.get("/")
async def root():
    loop = asyncio.get_running_loop()

    result = await loop.run_in_executor(None, blocking_function)
    return result

@app.get("/ok")
async def ok():
    return {"ok": 1}

if __name__ == "__main__":
    uvicorn.run(app, host="0.0.0.0", workers=1)

As I understand, the code will spawn another thread in the default ThreadExecutorPool and then execute the blocking function in the thread pool. On the other side, thinking about how the GIL works, the CPython interpreter will only execute a thread for 100 ticks and then it will switch to another thread to be fair and give other threads a chance to progress. In this case, what if the Python interpreter decides to switch to the threads where the blocking_function is executing? Will it block the who interpreter to wait for whatever remaining on the time.sleep(5)?

The reason I am asking this is that I have observed sometimes my application will block on the blocking_function, however I am not entirely sure what's in play here as my blocking_function is quite special -- it talks to a COM API object through the win32com library. I am trying to rule out that this is some GIL pitfalls I am falling into.

like image 272
Bob Fang Avatar asked Oct 26 '20 21:10

Bob Fang


1 Answers

Both time.sleep (as explained in this question) and the win32com library (according to this mailing list post) release the GIL when they are called, so they will not prevent other threads from making progress while they are blocking.

To answer the "high-level" question - "can run_in_executor ever (directly or indirectly) block the event-loop?" - the answer would only be "yes" if you used a ThreadPoolExecutor, and the code you executed in run_in_executor did blocking work that didn't release the GIL. While that wouldn't completely block the event loop, it would mean both your event loop thread and the executor thread could not run in parallel, since both would need to acquire the GIL to make progress.

like image 77
dano Avatar answered Nov 08 '22 01:11

dano