On 20/10/2012 1:33am, Greg Ewing wrote:
That's been bothering me, too. It seems like an interface accommodating the completion-based style will have to be *extremely* fat.
That's not just a burden for anyone implementing the interface, it's a problem for any library wanting to *wrap* it as well.
For example, to maintain separation between the async layer and the generator layer, we will probably want to have an AsyncSocket object in the async layer, and a separate GeneratorSocket in the generator layer that wraps an AsyncSocket.
If the AsyncSocket needs to provide methods for all the possible I/O operations that one might want to perform on a socket, then GeneratorSocket needs to provide its own versions of all those methods as well.
Multiply that by the number of different kinds of I/O objects (files, sockets, message queues, etc. -- there seem to be quite a lot of them on Windows) and that's a *lot* of stuff to be wrapped.
I don't see why a completion api needs to create wrappers for sockets. See http://pastebin.com/7tDmeYXz for an implementation of a completion api implemented for Unix (plus a stupid reactor class and some example server/client code). The AsyncIO class is independent of reactors, futures etc. The methods for starting an operation are recv(key, sock, nbytes, flags=0) send(key, sock, buf, flags=0) accept(key, sock) connect(key, sock, address) The "key" argument is used as an identifier for the operation. You wait for something to complete using wait(timeout=None) which returns a list of tuples of the form "(key, success, value)" representing completed operations. "key" is the identifier used when starting the operation, "success" is a boolean indicating whether an error occurred, and "value" is the return/exception value. To check whether there are any outstanding operations, use empty() (To make the AsyncIO class usable without a reactor one should probably implement a "filtered" wait so that you can restrict the keys you want to wait for.) -- Richard