开发者

Designing an async API in Python

(Note: this question is strictly about the design of the API, not about how to implement it; i.e. I only care about what the client of my API sees here, not what I have to do to make it work.)

In simple terms: I want to know the established pattern - if any - for explicit futures (aka promises, aka deferreds, aka tasks - names vary depending on the framework) in Python. Following is a more detailed description.

Consider a simple Python API like this:

def read_line():
   ...
s = read_line()
print(s)

This is a syncronous version - it will block if a line is not available yet. Suppose, now, that I want to provide a corresponding asynchronous (non-blocking) version that allows to register a callback to be invoked once the operation completes. E.g. a simple version could look like this:

def read_line_async(callback):
   ...
read_line_async(lambda s: print(s))

Now, in other languages and frameworks, there are often existing mandated or at least well-established patterns for such APIs. For example, in .NET prior to version 4, one would typically provide a pair of BeginReadLine/EndReadLine methods, and use the stock IAsyncResult interface to register callbacks and pass the resulting values. In .NET 4+, one uses System.Threading.Tasks, so as to enable all task combining开发者_Go百科 operators (WhenAll etc), and to hook up into C# 5.0 async feature.

For another example, in JavaScript, there's nothing to cover this in the standard library, but jQuery has popularized the "deferred promise" interface that is now separately specified. So if I were to write async readLine in JS, I would name it readLineAsync, and implement then method on the returned value.

What, if any, is the established pattern in Python land? Looking through the standard library, I see several modules offering asynchronous APIs, but no consistent pattern between them, and nothing like a standardized protocol for "tasks" or "promises". Perhaps there is some pattern that can be derived from popular third-party libraries?

I've also seen the (oft-mentioned in this context) Deferred class in Twisted, but it seems to be overengineered for a general-purpose promise API, and rather adapted to the specific needs of this library. It doesn't look like something that I could easily clone an interface for (without taking a dependency on them) such that our promises would interoperate well if the client uses both libraries together in his application. Is there any other popular library or framework that has an explicitly designed API for this, that I could copy (and interoperate with) without taking a direct dependency?


Okay, so I have found PEP-3148, which does have a Future class. I cannot quite use it as is, so far as I can see, because proper instances are only created by Executor, and that is a class to convert existing synchronous APIs to asynchrony by e.g. moving the synchronous call to a background thread. However, I can replicate exactly the methods provided by Future objects - they match very closely what I would expect, i.e. the ability to (blocking) query for result, cancel, and add a callback.

Does this sound like a reasonable approach? Should it, perhaps, be accompanied with a proposal to add an abstract base class for the generic "future" concept to Python standard library, just like Python collections have their ABCs.


Read the various "server" libraries for hints.

A good example is BaseHTTPServer

Specifically, the HTTPServer class definition shows how a "handler class" is provided.

Each request instantiates an instance of the handler class. That object then handles the request.

If you want to write "asynchronous I/O" with a "callback", you'd provide a ReadHandler class to your reader.

class AsyncReadHandler( object ):
    def input( self, line, server ):
        print( line )

read_line_async( AsyncReadHandler )

Something like that would follow some established design patterns.


Have you looked at decorators yet?

from threading import Thread

def addCallback(function):
    def result(parameters,callback):
        # Run the function.
        result = function(parameters)
        # Run the callback asynchronously.
        Thread(target=callback).start()
        # Run the callback synchronously.
        #callback()
        # Return the value of the function.
        return result
    return result

@ addCallback
def echo(value):
    print value

def callback():
    print 'Callback'

echo('Hello World!',callback)
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜