After reading a lot of question/answers on this subject as well as the official doc :
Questions / Answers :
- Python multiprocessing - starmap_async does not work where starmap does?
- multiprocessing.Pool.map_async doesn't seem to... do anything at all?
- Understand starmap_async() in multiprocessing programmation
...and many others
Official doc : HERE
I still don't understand the meaning of having the possibility to run "apparently" a non-blocking code, by calling starmap_async()
,
Since, as far as I understand, we need to call the wait()
or get()
method on it in order to make it run and get the actual result.
This is what those answer explains well :
https://stackoverflow.com/a/56462430/13000695
Pool's async-methods return objects which are conceptually "explicit futures", you need to call .get() to await and receive the actual result
https://stackoverflow.com/a/70674001/13000695
.wait() waits forever for the process to finish.
So : Those two methods will simply turn the non-blocking code into a blocking one since it will wait until this task has been completed.
I am looking for a way to run multiprocess while not blocking the main thread. I build a server using FastAPI library, which I plan to use asychronously, but currently the build_cache()
method will block the main thread and the WebServer will not receive incoming HTTP requests until the cache has been downloaded :
from multiprocessing.pool import Pool
from multiprocessing import cpu_count
def get_from_ftp(file_name):
flo = BytesIO()
ftp_server = FTP(ftp_url)
ftp_server.login()
ftp_server.retrbinary(f'RETR {file_name}', flo.write)
flo.seek(0)
# write file on disk...
async def build_cache():
with Pool(cpu_count() - 1) as pool:
some_files_to_download = ['file1', 'file2']
result = pool.starmap_async(get_from_ftp, some_files_to_download)
result.wait() # <=== This will block the main thread and the server will not be able to receive incoming requests
Then on my FastAPI main file :
app = FastAPI()
@app.on_event("startup")
async def startup():
await build_cache()
if __name__ == "__main__":
uvicorn.run(app, host="0.0.0.0", port=8000)