Python Twisted中的异步编程

30 投票
1 回答
9077 浏览
提问于 2025-04-11 09:19

我在用Twisted开发一个反向代理的时候遇到了一些麻烦。虽然它能工作,但感觉太复杂了,有点让人摸不着头脑。

有没有什么简单明了的例子,或者书籍里有关于异步程序结构的内容?我想要一些最佳实践的指南。当我完成我的程序时,希望能看到它的结构,而不是一团乱麻。

1 个回答

65

Twisted包含了很多示例,其中有一个特别的例子是“Finger演变”教程,它详细解释了一个异步程序是如何从一个小的核心逐渐发展成一个复杂的系统,里面有很多活动的部分。还有一个可能对你有帮助的教程是关于如何编写服务器的。

关于Twisted或者其他异步网络库(比如asyncoreMINAACE),要记住的关键是,你的代码只有在发生某些事情时才会被调用。我听到的最常让人感到“神秘”的部分就是回调的管理,比如Deferred。如果你习惯于编写一条直线的代码,只调用那些立即返回结果的函数,那么等待某个东西来回调你可能会让你感到困惑。但回调并没有什么神奇的地方,根本没有“魔法”。在最基本的层面上,反应器只是静静地等待少数几件事情发生:

  1. 数据通过连接到达(它会在一个协议上调用dataReceived
  2. 时间过去了(它会调用一个用callLater注册的函数)
  3. 连接被接受(它会在一个用listenXXXconnectXXX函数注册的工厂上调用buildProtocol
  4. 连接被断开(它会在相应的协议上调用connectionLost

每个异步程序都是通过连接这些事件开始的,然后启动反应器来等待它们的发生。当然,发生的事件会导致更多的事件被连接或断开,因此你的程序就这样继续运行。除此之外,异步程序的结构没有什么特别的地方;事件处理器和回调只是对象,你的代码以通常的方式运行。

这里有一个简单的“事件驱动引擎”,可以让你看到这个过程是多么简单。

# Engine
import time
class SimplestReactor(object):
    def __init__(self):
        self.events = []
        self.stopped = False

    def do(self, something):
        self.events.append(something)

    def run(self):
        while not self.stopped:
            time.sleep(0.1)
            if self.events:
                thisTurn = self.events.pop(0)
                thisTurn()

    def stop(self):
        self.stopped = True

reactor = SimplestReactor()

# Application    
def thing1():
    print 'Doing thing 1'
    reactor.do(thing2)
    reactor.do(thing3)

def thing2():
    print 'Doing thing 2'

def thing3():
    print 'Doing thing 3: and stopping'
    reactor.stop()

reactor.do(thing1)
print 'Running'
reactor.run()
print 'Done!'

在像Twisted这样的库的核心,主循环中的函数不是sleep,而是像select()poll()这样的操作系统调用,这些是通过像Python选择模块这样的模块提供的。我说“像”select,因为这个API在不同平台之间差异很大,几乎每个GUI工具包都有自己的版本。Twisted目前提供了一个抽象接口,支持14种不同的变体。这种API提供的共同点是,给你一种方式来说明“我在等待这些事件。去睡觉,直到其中一个发生,然后醒来告诉我是哪一个。”

撰写回答