[Web-SIG] [PEP 444] Future- and Generator-Based Async Idea
P.J. Eby
pje at telecommunity.com
Sat Jan 8 20:57:36 CET 2011
At 01:24 PM 1/8/2011 -0500, Paul Davis wrote:
>For contrast, I thought it might be beneficial to have a comparison
>with an implementation that didn't use async might look like:
>
>http://friendpaste.com/4lFbZsTpPGA9N9niyOt9PF
Compare your version with this one, that uses my revision of Alice's proposal:
def my_awesome_application(environ):
# do stuff
yield b'200 OK', [], ["Hello, World!"]
def my_middleware(app):
def wrapper(environ):
# maybe edit environ
try:
status, headers, body = yield app(environ)
# maybe edit response:
# body = latinize(body)
yield status, headers, body
except:
# maybe handle error
finally:
# maybe release resources
def my_server(app, httpreq):
environ = wsgi.make_environ(httpreq)
def process_response(result):
status, headers, body = result
write_headers(httpreq, status, headers)
Coroutine(body, body_trampoline, finish_response)
def finish_response(result):
# cleanup, if any
Coroutine(app(environ), app_trampoline, process_response)
The primary differences are that the server needs to split some of
its processing into separate routines, and response-processing done
by middleware has to happen in a while loop rather than a for loop.
>If your implementation requires that people change source code (yield
>vs return) when they move code between sync and async servers, doesn't
>that pretty much violate the main WSGI goal of portability?
The idea here would be to have WSGI 2 use this protocol exclusively,
not to have two different protocols.
>IMO, the async middleware is quite more complex than the current state
>of things with start_response.
Under the above proposal, it isn't, since you can't (only) do a for
loop over the response body; you have to write a loop and a
push-based handler as well. In this case, it is reduced to just
writing one loop.
I'm still not entirely convinced of the viability of the approach,
but I'm no longer in the "that's just crazy talk" category regarding
an async WSGI. The cost is no longer crazy, but there's still some
cost involved, and the use case rationale hasn't improved much.
OTOH, I can now conceive of actually *using* such an async API for
something, and that's no small feat. Before now, the idea held
virtually zero interest for me.
>Either way this proposal reminds me quite a bit of Duff's device [1].
>On its own Duff's device is quite amusing and could even be employed
>in some situations to great effect. On the other hand, any WSGI spec
>has to be understandable and implementable by people from all skill
>ranges. If its a spec that only a handful of people comprehend, then I
>fear its adoption would be significantly slowed in practice.
Under my modification of Alice's proposal, nearly all of the
complexity involved migrates to the server, mostly in the (shareable)
Coroutine implementation.
For an async server, the "arrange for coroutine(result) to be called"
operations are generally native to async APIs, so I'd expect them to
find that simple to implement. Synchronous servers just need to
invoke the waited-on operation synchronously, then pass the value
back into the coroutine. (e.g. by returning "pause" from the
trampoline, then calling coroutine(value, exc_info) to resume
processing after the result is obtained.)
More information about the Web-SIG
mailing list