Fork me on GitHub

Ivan-Site.com

gevent: gunicorn vs uWSGI

Following my previous benchmark I finally got around to benchmarking uWSGI with gevent and comparing its performance to gunicorn with gevent worker type. To do this you have to compile uWSGI and gevent from source, so I used the latest tagged releases at the time of the test, uWSGI 1.3 and gevent 1.0b4.

As it turns out, performance of the two servers is almost identical when using gevent...

I initiated the system exactly the same way as the last test, except for instead of installing uWSGI from pip I did it from their new github repo. I followed the guide in their wiki http://projects.unbit.it/uwsgi/wiki/Gevent for compiling uWSGI:

git clone git://github.com/unbit/uwsgi.git
cd uwsgi
git checkout 1.3
python uwsgiconfig.py --build gevent
sudo cp uwsgi /usr/local/bin/

I also had to install gevent from source as uWSGI only works with gevent 1.0+ and it's still in beta (and thus not on pypi):

# cython needed for gevent
sudo apt-get install cython
git clone git://github.com/SiteSupport/gevent.git
cd gevent
git checkout 1.0b4
sudo python setup.py install

After this you'll be able to run uwsgi with gevent loop engine ( --loop gevent parameter )

uwsgi -s 127.0.0.1:8001 --processes 4 --loop gevent --enable-threads --async 128 --disable-logging --wsgi-file greq.py

To see asynchronous performance increase for uWSGI, you need to actually use gevent in your application code. This is different from the way that gunicorn handles it as it would do all of that for you at the request level. I used grequests instead of requests, which wraps around requests with gevent.spawn when testing uWSGI. Doing this in gunicorn would actually result in slightly lower performance.

import grequests
def application(environ, start_response):
    status = '200 OK'
    r = grequests.get('http://10.1.1.2')
    r.send()
    output = r.response.content

    response_headers = [('Content-type', 'text/html'),
                         ('Content-Length', str(len(output)))]
    start_response(status, response_headers)
    return [output]

Just like the last test, I used ab and tested at multiple concurrency levels. Results are below:

gevent requests

gevent max requests

gevent time

As you can see, the results are pretty close with uWSGI having a slight edge in throughput in some cases and gunicorn having a slight advantage in request times. I think we can safely conclude that most of the work is being handled by gevent in this benchmark, so the server doesn't actually play a huge role in performance. That being said, gunicorn is a lot easier to install as it doesn't need manual compilation or beta versions of gevent.

Posted Sun 14 October 2012 by Ivan Dyedov in Python (Python, WSGI, gevent, gunicorn, uWSGI, benchmark, nginx, Ubuntu, Linux)