title: What is the difference between Uvicorn and Gunicorn+Uvicorn?
body: <p>What is the difference between deploying FastAPI apps dockerized using Uvicorn and <a href="https://github.com/tiangolo/uvicorn-gunicorn-fastapi-docker" rel="noreferrer">Tiangolo's Gunicorn+Uvicorn</a>? And why do my results show that I get a better result when deploying only using Uvicorn than Gunicorn+Uvicorn?</p>
  <p>When I searched in Tiangolo's documentation, it says:</p>
  <blockquote>
  <p>You can use Gunicorn to manage Uvicorn and run multiple of these concurrent processes. That way, you get the best of concurrency and parallelism.</p>
  </blockquote>
  <p>From this, can I assume that using this Gunicorn will get a better result?</p>
  <p>This is my testing using JMeter. I deployed my script to Google Cloud Run, and this is the result:</p>
  <p>Using Python and Uvicorn:</p>
  <p><a href="https://i.stack.imgur.com/iH8kd.png" rel="noreferrer"><img src="https://i.stack.imgur.com/iH8kd.png" alt="enter image description here" /></a></p>
  <p>Using Tiangolo's Gunicorn+Uvicorn:</p>
  <p><a href="https://i.stack.imgur.com/NJCYK.png" rel="noreferrer"><img src="https://i.stack.imgur.com/NJCYK.png" alt="enter image description here" /></a></p>
  <p>This is my Dockerfile for Python (Uvicorn):</p>
  <pre><code>FROM python:3.8-slim-buster
  RUN apt-get update --fix-missing
  RUN DEBIAN_FRONTEND=noninteractive apt-get install -y libgl1-mesa-dev python3-pip git
  RUN mkdir /usr/src/app
  WORKDIR /usr/src/app
  COPY ./requirements.txt /usr/src/app/requirements.txt
  RUN pip3 install -U setuptools
  RUN pip3 install --upgrade pip
  RUN pip3 install -r ./requirements.txt --use-feature=2020-resolver
  COPY . /usr/src/app
  CMD [&quot;python3&quot;, &quot;/usr/src/app/main.py&quot;]
  </code></pre>
  <p>This is my Dockerfile for Tiangolo's Gunicorn+Uvicorn:</p>
  <pre><code>FROM tiangolo/uvicorn-gunicorn-fastapi:python3.8-slim
  RUN apt-get update &amp;&amp; apt-get install wget gcc -y
  RUN mkdir -p /app
  WORKDIR /app
  COPY ./requirements.txt /app/requirements.txt
  RUN python -m pip install --upgrade pip
  RUN pip install --no-cache-dir -r /app/requirements.txt
  COPY . /app
  </code></pre>
  <p>You can see the error from Tiangolo's Gunicorn+Uvicorn. Is it caused by Gunicorn?</p>
  <p>Edited.</p>
  <p>So, in my case, I using lazy load method to load my Machine Learning model. This is my class to load the model.</p>
  <pre class="lang-py prettyprint-override"><code>class MyModelPrediction:
      # init method or constructor
      def __init__(self, brand):
          self.brand = brand
  
      # Sample Method
      def load_model(self):
          pathfile_model = os.path.join(&quot;modules&quot;, &quot;model/&quot;)
          brand = self.brand.lower()
          top5_brand = [&quot;honda&quot;, &quot;toyota&quot;, &quot;nissan&quot;, &quot;suzuki&quot;, &quot;daihatsu&quot;]
  
          if brand not in top5_brand:
              brand = &quot;ex_Top5&quot;
              with open(pathfile_model + f'{brand}_all_in_one.pkl', 'rb') as file:
                  brand = joblib.load(file)
          else:
              with open(pathfile_model + f'{brand}_all_in_one.pkl', 'rb') as file:
                  brand = joblib.load(file)
  
          return brand
  </code></pre>
  <p>And, this is my endpoint for my API.</p>
  <pre class="lang-py prettyprint-override"><code>@router.post(&quot;/predict&quot;, response_model=schemas.ResponsePrediction, responses={422: schemas.responses_dict[422], 400: schemas.responses_dict[400], 500: schemas.responses_dict[500]}, tags=[&quot;predict&quot;], response_class=ORJSONResponse)
  async def detect(
      *,
      # db: Session = Depends(deps.get_db_api),
      car: schemas.Car = Body(...),
      customer_id: str = Body(None, title='Customer unique identifier')
  ) -&gt; Any:
      &quot;&quot;&quot;
      Predict price for used vehicle.\n
      &quot;&quot;&quot;
      global list_detections
      try:
          start_time = time.time()
          brand = car.dict()['brand']
          obj = MyModelPrediction(brand)
  
          top5_brand = [&quot;honda&quot;, &quot;toyota&quot;, &quot;nissan&quot;, &quot;suzuki&quot;, &quot;daihatsu&quot;]
          if brand not in top5_brand:
              brand = &quot;non&quot;
  
          if usedcar.price_engine_4w[brand]:
              pass
          else:
              usedcar.price_engine_4w[brand] = obj.load_model()
              print(&quot;Load success&quot;)
  
          elapsed_time = time.time() - start_time
          print(usedcar.price_engine_4w)
          print(&quot;ELAPSED MODEL TIME : &quot;, elapsed_time)
  
          list_detections = await get_data_model(**car.dict())
  
          if list_detections is None:
              result_data = None
          else:
              result_data = schemas.Prediction(**list_detections)
              result_data = result_data.dict()
  
      except Exception as e:  # noqa
          raise HTTPException(
              status_code=500,
              detail=str(e),
          )
      else:
          if result_data['prediction_price'] == 0:
              raise HTTPException(
                  status_code=400,
                  detail=&quot;The system cannot process your request&quot;,
              )
          else:
              result = {
                  'code': 200,
                  'message': 'Successfully fetched data',
                  'data': result_data
              }
  
      return schemas.ResponsePrediction(**result)
  </code></pre>