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 :doc:`Async` mode.
- The :doc:`SignalFramework` is fully working with Gevent mode. Each handler will be executed in a dedicated greenlet. Look at :file:`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.
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
A 'gevent' build profile can be found in the :file:`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
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
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()
- 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.
uwsgi_buffering off;