Open In App

Multiprocessing in FastAPI

Last Updated : 09 Nov, 2023
Improve
Improve
Like Article
Like
Save
Share
Report

In this article, we are going to see what is multiprocessing, and how multiprocessing can utilize the system resources efficiently and can reduce the time taken to complete a big task. We will see the “concurrent.futures” module that is used for multiprocessing in FastAPI and then see how we can use it to download a big zip file from the server efficiently.

What is Multiprocessing?

A Process is an independent program having its own memory space, code, data, and system resources. Multiple processes run on the system independently of each other. Two processes will not have access to a shared resource simultaneously. Multiprocessing is the running of multiple processes at the same time on a multi-core CPU. Multiprocessing helps in utilizing the CPU resources efficiently by achieving true data parallelism.

There are two types of time-bounding operations I/O bound and CPU bound. In I/O bound operation more time is consumed in input-output operation and in CPU bound task process consumes more CPU time. Multiprocessing is mostly used when CPU-bound tasks need to be completed because the task can be divided into multiple processes and those processes can run on multiple processors at the same time.

Downloading Multiple images using Multiprocessing

We are going to create an API that will download a zip file consisting of 10 high-resolution images from the server. The server first has to download the images, zip them, and then send them to the client. Now if the images are of high resolution it will take a lot of time if the server download the images synchronously. For downloading the image faster we can create 10 processes each responsible for downloading different images and writing the downloaded image in the zip file.

Multiprocessing-in-FastAPI

What is “concurrent.futures” Module ?

We are going to use the concurrent.futures module which is used to execute tasks in parallel. It provides two main classes ThreadPoolExecutor and ProcessPoolExecutor which can be used to submit the tasks that need to be run in parallel. The ProcessPoolExecutor will create a set of processes and tasks are assigned to one of the process that is available. For example we can create an instance of ProcessPoolExecutor and then pass the function that needs be executed in parallel by calling the submit method on the executor object. The executor will then assign this function to one of the processes in the process pool.

Setting up the Project

We are going to create a “/download” endpoint which will download a zip file consisting of 10 blurred images. At the server side we are going to download the images, zip it and send it back as response to the user. Create a folder named multiprocessing_gfg and create a file named “app.py” in it and copy paste the below code:

  • The /download endpoint is defined as an asynchronous FastAPI route (async def uploadfile()).
  • Inside this endpoint, a list called list is initialized to store the futures returned by the ProcessPoolExecutor. These futures represent the concurrent image processing tasks.
  • The concurrent.futures.ProcessPoolExecutor is used to manage a pool of worker processes. Within a loop, it submits the process_image function as a task with the URL and an index (i) as arguments. This means that up to 10 image processing tasks can run concurrently, thanks to the ProcessPoolExecutor.
  • The concurrent.futures.wait function is used to wait for all submitted tasks to complete before proceeding.
  • After all image processing tasks are done, the add_images_to_zip function is called to add the processed images to a ZIP file.
  • Finally, a FileResponse is returned with the ZIP file as an attachment.

Python3




import io
from fastapi import FastAPI
from PIL import Image, ImageFilter
from pathlib import Path
import concurrent.futures
import zipfile
from fastapi.responses import FileResponse
import requests
app = FastAPI()
def process_image(url, count):
    try:
        response = requests.get(url)
        image = Image.open(io.BytesIO(response.content))
        image = image.filter(ImageFilter.GaussianBlur(1))
        temp_image_path =Path(f"temp_{count}.jpg")
        image.save(temp_image_path)
 
    except Exception as e:
        print(e)
 
def add_images_to_zip(zipf):
    try:
        for i in range(10):
            image_path = Path(f"temp_{i}.jpg")
            zipf.write(image_path)
            image_path.unlink() 
    except Exception as e:
        print(e)
 
 
@app.get("/download")
async def uploadfile():
    try:
        url = "https://picsum.photos/200/300"
        list = []
        zip_file_path = Path("processed_images.zip")
        with zipfile.ZipFile(zip_file_path, 'w', zipfile.ZIP_DEFLATED) as zipf:
            with concurrent.futures.ProcessPoolExecutor() as executor:
                for i in range(10):
                    futures = executor.submit(process_image, url, i)
                    print(futures)
                    list.append(futures)
                concurrent.futures.wait(list)
                add_images_to_zip(zipf)
        return FileResponse(zip_file_path, headers={"Content-Disposition": "attachment; filename=processed_images.zip"})
    except Exception as e:
        print(e)
        return {"message": e}


Deployement of the Project

To run the fastAPI application created above we are going to use the uvicorn which is an ASGI server used to deploy the fastAPI web application. Run the below command on the terminal :

python -m uvicorn app::app --reload

gfg_multiprocessing_fastapi_image_1

In the above line we specified the file name app which is going to be used as our application. Then we specified the app instance we created of the FastAPI class. “–reload” tag is used to automatically reload the server whenever changes in the app.py files are detected.

Open web browser and copy paste the below URL:

http://127.0.0.1:8000/download

The above url will download the zip file on your system.

Output



Like Article
Suggest improvement
Share your thoughts in the comments

Similar Reads