The Gevent loop engine¶
Gevent is an amazing non-blocking Python network library built on top of libev and greenlet. Even though uWSGI supports Greenlet as suspend-resume/greenthread/coroutine library, it requires a lot of effort and code modifications to work with gevent. The gevent plugin requires gevent 1.0.0 and uWSGI asynchronous/non-blocking modes (updated to uWSGI 1.9) mode.
- The SignalFramework is fully working with Gevent mode. Each handler will be executed in a dedicated greenlet. Look at tests/ugevent.py for an example.
- uWSGI multithread mode (threads option) will not work with Gevent. Running Python threads in your apps is supported.
- Mixing uWSGI’s Async API with gevent’s is EXPLICITLY FORBIDDEN.
Building the plugin (uWSGI >= 1.4)¶
The gevent plugin is compiled in by default when the default profile is used. Doing the following will install the python plugin as well as the gevent one:
pip install uwsgi
Building the plugin (uWSGI < 1.4)¶
A ‘gevent’ build profile can be found in the buildconf directory.
python uwsgiconfig --build gevent # or... UWSGI_PROFILE=gevent make # or... UWSGI_PROFILE=gevent pip install git+git://github.com/unbit/uwsgi.git # or... python uwsgiconfig --plugin plugins/gevent # external plugin
Running uWSGI in gevent mode¶
uwsgi --gevent 100 --socket :3031 --module myapp
or for a modular build:
uwsgi --plugins python,gevent --gevent 100 --socket :3031 --module myapp
the argument of –gevent is the number of async cores to spawn
A crazy example¶
The following example shows how to sleep in a request, how to make asynchronous network requests and how to continue doing logic after a request has been closed.
import gevent import gevent.socket def bg_task(): for i in range(1,10): print "background task", i gevent.sleep(2) def long_task(): for i in range(1,10): print i gevent.sleep() def application(e, sr): sr('200 OK', [('Content-Type','text/html')]) t = gevent.spawn(long_task) t.join() yield "sleeping for 3 seconds...<br/>" gevent.sleep(3) yield "done<br>" yield "getting some ips...<br/>" urls = ['www.google.com', 'www.example.com', 'www.python.org', 'projects.unbit.it'] jobs = [gevent.spawn(gevent.socket.gethostbyname, url) for url in urls] gevent.joinall(jobs, timeout=2) for j in jobs: yield "ip = %s<br/>" % j.value gevent.spawn(bg_task) # this task will go on after request end
uWSGI uses native gevent api, so it does not need monkey patching. That said, your code may need it, so remember to call gevent.monkey.patch_all() at the start of your app. As of uWSGI 1.9, the convenience option --gevent-monkey-patch will do that for you. Please note that uWSGI does monkey patching before your application starts, not before your application loads. So if you are loading other modules while loading your application you may still need to call gevent.monkey.patch_all() yourself.
A common example is using psycopg2_gevent with django. Django will make a connection to postgres for each thread (storing it in thread locals).
As the uWSGI gevent plugin runs on a single thread this approach will lead to a deadlock in psycopg. Enabling monkey patch will allow you to map thread locals to greenlets (though you could avoid full monkey patching and only call gevent.monkey.patch_thread()) and solves the issue:
import gevent.monkey gevent.monkey.patch_thread() import gevent_psycopg2 gevent_psycopg2.monkey_patch()
or (to monkey patch everything)
import gevent.monkey gevent.monkey.patch_all() import gevent_psycopg2 gevent_psycopg2.monkey_patch()
Notes on clients and frontends¶
- If you’re testing a WSGI application that generates a stream of data, you should know that curl by default buffers data until a newline. So make sure you either disable curl’s buffering with the -N flag or have regular newlines in your output.
- If you are using Nginx in front of uWSGI and wish to stream data from your app, you’ll probably want to disable Nginx’s buffering.