28

I'm writing flask application that accepts POST requests with json data. I noticed huge differences in response time based on data size being passed to application. After debugging I narrowed down issue to the line where I was retrieving json data from request object. It may be important to note that testing was done on flask development server.

start = time.time()
resp = json.dumps(request.json)
return str(time.time() - start)

I timed this line and for data of 1024 (probably not coincidence) and less characters this took 0.002s and for anything over 1024 over 1 second! What is happening here? Is this the limitation of development server?

EDIT: Same thing happens for getting POST data through request.form.get('somedata') with content lenght over 1024

EDIT: I couldn't replicate issue with same example served by Apache

EDIT: I started digging into Werkzeug module and found that slowness occurs when reading response message self._read(to_read) in wsgi.py module which is passed from BaseHTTPRequestHandler. Still don't know why so slow.


Here's environment details: Ubuntu - 10.04 Python - 2.6.5 Flask - 0.9 Werkzeug - 0.8.3

marcin_koss
  • 5,763
  • 10
  • 46
  • 65
  • May be related? http://stackoverflow.com/questions/11150343/slow-requests-on-local-flask-server – barracel Nov 22 '12 at 16:34
  • barracel this is not it. – marcin_koss Nov 23 '12 at 20:34
  • 3
    Can you replicate this with any other standalone WSGI servers? such as gunicorn, Tornado, ... see http://flask.pocoo.org/docs/deploying/wsgi-standalone/ – Markus Unterwaditzer Nov 23 '12 at 21:17
  • Markus, good idea. I tried Tornado and can't replicate the problem. – marcin_koss Nov 23 '12 at 22:20
  • What version of Flask, Werzeug are you using? What platform? Python version? I can't reproduce. – soulseekah Nov 25 '12 at 00:22
  • soulseekah, check the bottom of my post, I updated it. – marcin_koss Nov 26 '12 at 01:33
  • 3
    I have had problems using BaseHTTPRequestHandler in bottle, not flask. But it may be the same problem, the development environment is trying to resolve the ip address into host names, so they delay could be that lookup timing out. http://blog.est.im/post/34288214582 Maybe this is a strecht, but it might lead you in right direction. – i_4_got Nov 30 '12 at 18:20
  • The line you're timing does 2 distinctly separate operations 1) retrieve the POST content 2) JSON encode that content. Have you timed 1 & 2 seperately, to be certain which is taking the time? – Alex Willmer Dec 01 '12 at 15:29
  • Yes I did. Check my last edit in bold. It seems like BaseHTTPRequestHandler is responsible for this. – marcin_koss Dec 01 '12 at 19:29
  • Did you resolve this? Perhaps a test case to the appropriate python mailing list for BaseHTTPRequestHandler? – Ken Kinder Dec 07 '12 at 20:22

3 Answers3

6

The flask development server is expected to be slow. From http://flask.pocoo.org/docs/deploying/:

You can use the builtin server during development, but you should use a full deployment option for production applications. (Do not use the builtin development server in production.)

As Marcus mentioned in the comments, another WSGI server like gunicorn or tornado would be much faster and more reliable, so definitely use one of those for deployment and benchmarking.

If you're worried about working quickly during development, you can use gunicorn in development just like you would in deployment. If you're deploying to heroku, for example, you can run "foreman start" and the gunicorn server will start right up.

Ryan Shea
  • 4,252
  • 4
  • 32
  • 32
3

I had this problem on a line like this, it was taking about 1.0 second! It's in a flask post handler:

username=request.form.get('username')

I was testing it with curl -F:

curl -F username="x" http://127.0.0.1:5000/func

I just changed -F to -d and it got 0.0004 seconds!!!

curl -d username="x" http://127.0.0.1:5000/func

I think flask has a problem to retrieving "multipart/form-data" content-type.

iman
  • 21,202
  • 8
  • 32
  • 31
1

If you use curl to send a request, Expect: 100-continue might cause the behavior. I met a similar behavior with uwsgi, flask and curl. What happens in my case are the following:

  • If the request body size is larger than 1024 byte, curl posts data with Expect: 100-continue header.
  • However, uwsgi can't deal with the header. So the uwsgi doesn't respond 100-continue.
  • curl waits for the100-continue response until about one second time-out.

When curl sends 100-continue | Georg's Log was useful for me to know the curl behavior.

shotarok
  • 11
  • 1