Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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 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?

like image 245
Pavel Minaev Avatar asked Sep 02 '11 02:09

Pavel Minaev


People also ask

How do you create asynchronous API in Python?

We can write asynchronous code with Python by using a library called Asyncio, though. Python has another library called Aiohttp that is an HTTP client and server based on Asyncio. Thus, we can use Asyncio to create asynchronous API calls. This is useful for optimizing code.

Can you do async in Python?

Since Python 3.5, it is possible to use asynchronism in your scripts. This evolution allowed the use of new keywords async and await along with the new module asyncio. Async and Await were firstly introduced in C#, in order to structure non-blocking code in a similar fashion as you would write blocking code.

Can flask handle asynchronous?

Async functions require an event loop to run. Flask, as a WSGI application, uses one worker to handle one request/response cycle. When a request comes in to an async view, Flask will start an event loop in a thread, run the view function there, then return the result.


2 Answers

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.

like image 191
Pavel Minaev Avatar answered Sep 29 '22 20:09

Pavel Minaev


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.

like image 30
S.Lott Avatar answered Sep 29 '22 20:09

S.Lott