[Web-SIG] Server-side async API implementation sketches

Alice Bevan–McGregor alice at gothcandy.com
Mon Jan 10 01:39:03 CET 2011


On 2011-01-09 09:26:19 -0800, P.J. Eby said:
> By the way, I don't really see the point of the new sketches you're doing...

I'm sorry.

> ...as they aren't nearly as general as the one I've already done, but 
> still have the same fundamental limitation: wsgi.input.

You missed the point entirely, then.

> If wsgi.input offers any synchronous methods...

Regardless of whether or not wsgi.input is implemented in an async way, 
wrap it in a future and eventually get around to yielding it.  Problem 
/solved/.  Identical APIs for both sync and async, and if you have an 
async server but haven't gotten around to implementing your own 
executor yet, wrapping the blocking read call in a future also solves 
the problem (albeit not in the most efficient way).

I.e. wrap every call to a wsgi.input method by passing it to wsgi.submit.

> ...then they must be used from a future and must some how raise an 
> error when called from within the application -- otherwise it would 
> block, nullifying the point ofhaving a generator-based API.

See above.  No extra errors, nothing really that insane.

> If it offers only asynchronous methods, OTOH, then you can't pass 
> wsgi.input to any existing libraries (e.g. the cgi module).

Describe to me how a function can be suspended (other than magical 
greenthreads) if it does not yield; if I knew this, maybe I wouldn't be 
so confused.

> The latter problem is the worse one, because it means that the 
> translation of an app between my original WSGI2 API and the current 
> sketch is no longer just "replace 'return' with 'yield'".

I've deviated from your sketch, obviously, and any semblance of 
yielding a 3-tuple.  Stop thinking of my example code as conforming to 
your ideas; it's a new idea, or, worst case, a narrowing of an idea 
into its simplest form.

> The only way this would work is if WSGI applications are still allowed 
> to be written in a blocking style.  Greenlet-based frameworks would 
> have no problem with this, of course, but servers like Twisted would 
> still have to run WSGI apps in a worker thread pool, just because they 
> *might* block.

Then that is not acceptable and "would not work".  The mechanics of 
yielding futures instances allows you to (in your server) implement the 
necessary async code however you wish while providing a uniform 
interface to both sync and async applications running on sync and async 
servers.  In fact, you would be able to safely run a sync application 
on an async server and vice-versa.  You can, on an async server:

:: Add a callback to the yielded future to re-schedule the application 
generator.

:: If using greenthreads, just block on future.result() then 
immediately wake up the application generator.

:: Do other things I can't think of because I'm still waking up.

The first solution is how Marrow HTTPd would operate.

> If we're okay with this as a limitation, then adding _async method 
> variants that return futures might work, and we can proceed from there.

That is not optimum, because now you have an optional API that 
applications who want to be compatible will need to detect and choose 
between.

> Mostly, though, it seems to me that the need to be able to write 
> blocking code does away with most of the benefit of trying to have a 
> single API in the first place.

You have artificially created this need, ignoring the semantics of 
using the server-specific executor to detect async-capable requests and 
the yield mechanics I suggested; which happens to be a single, coherent 
API across sync and async servers and applications.

	- Alice.




More information about the Web-SIG mailing list