0

This is not a duplicate of this question

I am trying to understand how django handles multiple requests. According to this answer django is supposed to be blocking parallel requests. But I have found this is not exactly true, at least for django 3.1. I am using django builtin sever.

So, in my code(view.py) I have a blocking code block that is only triggered in a particular situation. It takes a very long to complete the request for this case. This is the code for view.py

from django.shortcuts import render
import numpy as np

def insertionSort(arr): 
  for i in range(1, len(arr)): 
    key = arr[i] 
    j = i-1
    while j >=0 and key < arr[j] : 
            arr[j+1] = arr[j] 
            j -= 1
    arr[j+1] = key

def home(request):
   a = request.user.username
   print(a)
   id = int(request.GET.get('id',''))

   if id ==1:
       arr = np.arange(100000)
       arr = arr[::-1]
       insertionSort(arr) 
       # print ("Sorted array is:") 
       # for i in range(len(arr)): 
       #     print ("%d" %arr[i]) 
   return render(request,'home/home.html')

so only for id=1 it will execute the blocking code block. But for other cases, it is supposed to work normally.

Now, what I found is, if I make two multiple requests, one with id=1 and another with id=2, second request does not really get blocked but takes longer time to get data from django. It takes ~2.5s to complete if there is another parallel blocking request. Otherwise, it takes ~0.02s to get data.

These are my python codes to make the request:

malicious request:

from concurrent.futures import as_completed
from pprint import pprint
from requests_futures.sessions import FuturesSession

session = FuturesSession()

futures=[session.get(f'http://127.0.0.1:8000/?id=1') for i in range(3)]
start = time.time()
for future in as_completed(futures):
    resp = future.result()
    # pprint({
    #     'url': resp.request.url,
    #     'content': resp.json(),
    # })

roundtrip = time.time() - start
print (roundtrip)

Normal request:

import logging
import threading
import time
import requests

if __name__ == "__main__":
    
    # start = time.time()
    while(True):
        print(requests.get("http://127.0.0.1:8000/?id=2").elapsed.total_seconds())
        time.sleep(2)

I will be grateful if anyone can explain how Django is serving the parallel requests in this case.

Masudul Hasan
  • 137
  • 2
  • 17

1 Answers1

0

There is an option to use --nothreading when you start the server. From what you described it's possible the blocking task finished in 2 seconds. Easier way to test is to just use time.sleep(10) for testing purposes.

Tim
  • 3,178
  • 1
  • 13
  • 26
  • the blocking task takes more than 2s to finish, that's for sure. I timed the blocking request separately to make sure that. – Masudul Hasan Feb 22 '21 at 23:50
  • Have you tried running with the `--nothreading` option? I remember it's not very robust and that's why it's not recommended to deploy with the built-in server. – Tim Feb 23 '21 at 00:11