在Python中设计异步API

时间:2011-09-02 02:07:42

标签: python asynchronous future api-design promise

(注意:这个问题严格关于API的设计,而不是关于如何实现它;即我只关心我的API的客户端在这里看到的,而不是我所拥有的做它的工作。)

简单来说:我想知道Python中已建立的模式 - 如果有的话 - explicit futures(又名承诺,又称延期,又名任务 - 名称因框架而异)。以下是更详细的说明。

考虑一个像这样的简单Python API:

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

这是一个同步版本 - 如果一条线路尚不可用,它将阻止。现在假设我想提供一个相应的异步(非阻塞)版本,它允许注册一个操作完成后调用的回调。例如。一个简单的版本可能如下所示:

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

现在,在其他语言和框架中,通常存在针对此类API的强制或至少完善的模式。例如,在版本4之前的.NET中,通常会提供一对BeginReadLine / EndReadLine方法,并使用stock IAsyncResult接口来注册回调并传递结果值。在.NET 4+中,使用System.Threading.Tasks,以便启用所有任务组合运算符(WhenAll等),并连接到C#5.0 async功能。

另一个例子,在JavaScript中,标准库中没有任何内容可以覆盖它,但是jQuery已经推广了现在为separately specified的“延迟承诺”界面。因此,如果我在JS中编写异步readLine,我会将其命名为readLineAsync,并对返回的值实现then方法。

如果有的话,Python领域的既定模式是什么?通过标准库,我看到几个提供异步API的模块,但它们之间没有一致的模式,没有像“任务”或“承诺”的标准化协议。也许有一些模式可以从流行的第三方库中获得?

我也看到了Twisted中的(在此上下文中经常提及)Deferred类,但它似乎是一个通用的promise API过度设计,而是适应了这个库的特定需求。它看起来不像我可以轻松地克隆接口(不依赖于它们),这样如果客户端在他的应用程序中同时使用两个库,我们的promise将很好地互操作。是否有任何其他流行的库或框架具有明确设计的API,我可以复制(和互操作)而不需要直接依赖?

3 个答案:

答案 0 :(得分:6)

好的,所以我找到了PEP-3148,它有一个Future类。就我所知,我不能完全按原样使用它,因为正确的实例仅由Executor创建,并且这是一个将现有的同步API转换为异步的类,例如:将同步调用移动到后台线程。但是,我可以完全复制Future个对象提供的方法 - 它们与我期望的非常接近,即(阻塞)查询结果,取消和添加回调的能力。

这听起来像是一种合理的做法吗?或许它应该伴随着向Python标准库添加通用“未来”概念的抽象基类的提议,就像Python集合有ABCs一样。

答案 1 :(得分:1)

阅读各种“服务器”库以获取提示。

一个很好的例子是BaseHTTPServer

具体来说,HTTPServer类定义显示了如何提供“处理程序类”。

每个请求都实例化一个处理程序类的实例。然后该对象处理请求。

如果您想使用“回调”编写“异步I / O”,则需要为您的读者提供ReadHandler课程。

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

read_line_async( AsyncReadHandler )

这样的事情将遵循一些既定的设计模式。

答案 2 :(得分:0)

你看过decorators了吗?

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)