What's the relation of the (apparently undocumented) gevent_wsgi and gevent_pywsgi to the "plain" gevent worker type?
gevent worker is our own worker using our wsgi parser, while otheres are gevent parsers.
Sorry to bump a 7 year old issue, but I was recently stuck with this same question for about a week.
I think that better documentation should be made for these 3 worker types.
Short summary of the week: I was experiencing identical performance for the sync and gevent workers, which was really confounding me. After looking at the source code, I discovered the gevent_pywsgi type which dramatically increased my performance.
Just curious, what is the purpose of the gevent worker option?
gevent_pywsgi
and gevent_wsgi
are the same. Names provided for backward compatibility. We could deprecate and remove one to make it slightly less confusing.
The rest is as described in the comment above. The regular gevent
uses our parser code, while _wsgi
uses one from Gevent.
If you find that gevent_pywsgi
increases performance, that would not be a surprise. However, if you find identical performance between sync
and gevent
then it seems like you are not getting much benefit from gevent
itself and therefore the only speed you get from gevent_pywsgi
is from the parsing code.
You may want to try the gevent
worker until you figure out the bottleneck, and whether you need asynchronous workers at all. Also, maybe you can say more about what you mean by performance: throughput (requests per second), latency (minimum), latency (average), etc. The sync
and gevent
workers _are_ different.
Just curious, what is the purpose of the gevent worker option?
To patch the blocking I/O functions of the standard library to use the gevent hub and handle concurrent requests in greenlets. If you need to handle a high volume of concurrent requests and your application performs a lot of waiting on I/O (database, streaming responses, upstream requests, etc) then gevent
can be a good choice.
@tilgovi here is a recent stack overflow I made regarding this issue
I was looking to improve throughput on a basic Flask hello world
, and could not get above 125RPS with either the sync
or gevent
worker type.
Could you clarify the following for me? I'm still a bit confused.:
The regular gevent uses our parser code
What do you mean by parser
?
In addition, looking at the source code of Gunicorn it seems that with -k gevent
, the gevent.server.StreamServer
is type is used, and with -k gevent_pywsgi
, the gevent.pywsgi.WSGIServer
type is used.
A basic hello world application is unlikely to see any performance improvement from gevent, especially if the benchmark is run locally or on a high performance network. The reason for this is that gevent only switches greenlets when performing I/O operations that would block. If you can receive the entire HTTP request in a single recv()
call and respond with a single send()
call, you are more or less doing what the sync worker is doing. The benefit of gevent is when your application has to wait on slow connections or upstream connections (like connections to a database or external API). Using gevent lets your application handle other requests at the same time it's waiting for those operations.
With gevent
worker type we use the gevent.server.StreamServer
to create a TCP server. That handles the transport layer, but we still need to parse the stream for HTTP requests, create the WSGI environment, call the WSGI application with the environment, and serialize an HTTP response.
The Gunicorn parser code is in message.py
.
With the gevent_pywsgi
worker, the parsing logic from gevent can be found in pywsgi.py
.
Thank you for the through explanations @tilgovi , its much appreciated!
Most helpful comment
A basic hello world application is unlikely to see any performance improvement from gevent, especially if the benchmark is run locally or on a high performance network. The reason for this is that gevent only switches greenlets when performing I/O operations that would block. If you can receive the entire HTTP request in a single
recv()
call and respond with a singlesend()
call, you are more or less doing what the sync worker is doing. The benefit of gevent is when your application has to wait on slow connections or upstream connections (like connections to a database or external API). Using gevent lets your application handle other requests at the same time it's waiting for those operations.With
gevent
worker type we use thegevent.server.StreamServer
to create a TCP server. That handles the transport layer, but we still need to parse the stream for HTTP requests, create the WSGI environment, call the WSGI application with the environment, and serialize an HTTP response.The Gunicorn parser code is in
message.py
.With the
gevent_pywsgi
worker, the parsing logic from gevent can be found inpywsgi.py
.