[Twisted-web] Re: [Web-SIG] WSGI woes
Phillip J. Eby
pje at telecommunity.com
Fri Sep 17 01:57:59 CEST 2004
At 07:16 PM 9/16/04 -0400, Peter Hunt wrote:
>Alan, that design looks okay. A bit complex, but it works well once
>you sit down to look at it.
>
>It would be nice if applications that didn't need a separate thread
>didn't use one up, so performance-oriented programmers (like the
>Twisted/Nevow guys) won't be able to have that excuse. Perhaps
>start_response() could have a "threaded" boolean optional argument
>that defaults to true which decides whether or not the iterable will
>be called in a separate thread. This, of course, requires that the
>application callable itself doesn't have any blocking code.
>
>Does this requirement overcomplicate things?
Yes. The vast majority of existing web applications are synchronous, and
so are a significant number of Python web server environments that would
run WSGI applications. Therefore the WSGI "common case" is to have
synchronous behavior, and WSGI is most efficient with either a synchronous
server/gateway, or a "half-async" server/gateway (i.e., one that runs
application code in a thread pool, separate from the main I/O thread.)
The few applications that can behave in a non-blocking fashion, can and
should use the iterable interface to provide their output, producing empty
strings when they are not yet ready to produce output. (Plus, when such
applications are run in a synchronous server or gateway, they might as well
behave synchronously, since they will actually incur more overhead by
trying to be asynchronous!)
The only scenario that isn't served by this approach is a single-threaded,
asynchronous server with no threading capability. However, such a server
*cannot* be WSGI-compatible and still serve multiple requests, and there is
no way around that without forcing *every* application to be asynchronous,
which just isn't an acceptable tradeoff. The idea of having a flag
(whether passed to start_response, or introspected on the application
object, etc.) doesn't help the fact that the server still has to be able to
*have* multiple threads in such a case.
Note, by the way, that the need for a second thread is caused by having a
possible difference between the synchrony model of a server and an
application. That is, if both are synchronous or both are asynchronous, no
threading is required. However, a server is not limited to running just
*one* application, so in the general case, a given server has to be able to
handle both.
However, since the common case is for apps to be synchronous, then the
common case for an asynchronous server is that it must be threaded, and the
common case for a synchronous server is that it need not be
threaded. Thus, logically, the case of an asynchronous application is the
"odd one out", in the sense that it is the only one that ever forces
additional threading, beyond what was inherently required for that server
model.
In other words, an async server has to have threading in the common case,
and a synchronous application doesn't. So, an async app in an async server
doesn't *add* any threading requirement: the async server already has to
have an I/O thread and at least one application thread. And a synchronous
app doesn't add any additional threading requirements to either kind of
server, for the same reason. Only an asynchronous application in a
synchronous server forces any extra overhead beyond the effective default
required threading configuration. Thus, it makes sense (to me, anyway) to
in that case put the burden on the asynchronous application to manage
communication with its extra thread, if any, or to have it adapt to local
circumstances and behave synchronously (since that's more efficient in that
case).
But in the end, all of this comes down to a basically simple idea: I think
that in WSGI, synchronous applications should be simple, and asynchronous
applications possible, because that will best support the goals of the PEP.
More information about the Web-SIG
mailing list