哪个Python异步库最适合我的代码? Asyncore?扭曲?

时间:2010-12-08 05:08:28

标签: python asynchronous twisted asyncore

我正在制作一个程序,它将同时从两个“网络资源”中读取。我想尝试一种异步方法,而不是使用线程。这让我想知道使用哪个库...

我想出了一些简单的示例代码,它可以演示我的程序将要执行的操作:

import sniffer

def first():
    for station in sniffer.sniff_wifi():
        log(station.mac())

def second():
    for station in sniffer.sniff_ethernet():
        log(station.mac())

first()
second()

两个sniffer方法看起来像这样:

def sniff_wifi(self):

    while True:
        yield mac_address

while True循环显然会阻止它们。

我想使用asyncore,因为它是标准库的一部分。没有第三方依赖是奖金。但是,如果你建议我这样做,那并不意味着我不会使用它......

我可以实现我想用asyncore做的事情吗?如果是这样,你能告诉我如何将我的示例代码转换为'asyncore代码'吗?你知道任何好的asyncore教程吗?

3 个答案:

答案 0 :(得分:50)

Twisted在几乎所有方面都更好。它更便携,更功能,更简单,更具可扩展性,更好的维护,更好的文档记录,它可以制作美味的煎蛋卷。无论如何,Asyncore已经过时了。

很难在短答案中展示Twisted优越的所有方式(我如何演示http / dns / ssh / smtp/pop/imap / { {3}} / irc/xmpp / process-spawning服务器在一个简短的例子中?),所以我将集中讨论人们似乎对Twisted的一个最常见的误解:它在某种程度上更复杂或者比asyncore更难使用。

让我们从asyncore示例开始。为了避免有偏见的演示,我将使用其他人仍然喜欢asyncore的例子。这是一个简单的异步核心示例multi-threading(由于简洁而省略了注释)。

首先,这是服务器:

import asyncore, socket

class Server(asyncore.dispatcher):
    def __init__(self, host, port):
        asyncore.dispatcher.__init__(self)
        self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
        self.bind(('', port))
        self.listen(1)

    def handle_accept(self):
        socket, address = self.accept()
        print 'Connection by', address
        EchoHandler(socket)

class EchoHandler(asyncore.dispatcher_with_send):
    def handle_read(self):
        self.out_buffer = self.recv(1024)
        if not self.out_buffer:
            self.close()

s = Server('', 5007)
asyncore.loop()

这是客户:

import asyncore, socket

class Client(asyncore.dispatcher_with_send):
    def __init__(self, host, port, message):
        asyncore.dispatcher.__init__(self)
        self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
        self.connect((host, port))
        self.out_buffer = message

    def handle_close(self):
        self.close()

    def handle_read(self):
        print 'Received', self.recv(1024)
        self.close()

c = Client('', 5007, 'Hello, world')
asyncore.loop()

有一些模糊的情况,这些代码无法正确处理,但解释它们是无聊和复杂的,代码已经使这个答案足够长。

现在,这里有一些基本相同的代码,使用Twisted。首先,服务器:

from twisted.internet import reactor, protocol as p

class Echo(p.Protocol):
    def dataReceived(self, data):
        self.transport.write(data)

class EchoFactory(p.Factory):
    def buildProtocol(self, addr):
        print 'Connection by', addr
        return Echo()

reactor.listenTCP(5007, EchoFactory())
reactor.run()

现在,客户:

from twisted.internet import reactor, protocol as p

class EchoClient(p.Protocol):
    def connectionMade(self):
        self.transport.write(self.factory.data)

    def dataReceived(self, data):
        print 'Received:', data
        self.transport.loseConnection()

class EchoClientFactory(p.ClientFactory):
    protocol = EchoClient
    def __init__(self, data):
        self.data = data

reactor.connectTCP('localhost', 5007, EchoClientFactory('Hello, world'))
reactor.run()

有几件事我想引起你的注意。首先,扭曲的例子缩短了25%,即使对于这个微不足道的事情也是如此。 asyncore有40行,Twisted只有30行。随着协议变得越来越复杂,这种差异将越来越大,因为您需要为Twisted提供的asyncore编写越来越多的支持代码。

其次,Twisted提供了完全抽象。使用asyncore示例,您必须使用socket模块来进行实际的网络连接; asyncore仅提供多路复用。如果您需要taken from Richard Jones' weblog,这是一个问题。这也意味着asyncore完全缺乏在其他平台上进行异步子进程通信的工具;你不能将任意文件描述符填充到Windows上的select()调用中。

第三,Twisted示例是传输中立EchoEchoFactory以及EchoClientEchoClientFactory都不是TCP特有的。您可以将这些类放入可通过SSH,SSL或UNIX套接字或管道连接的库中,只需更改底部的connectTCP / listenTCP调用即可。这很重要,因为在协议逻辑中直接支持TLS之类的东西非常棘手。例如,TL​​S中的“写入”将触发较低级别的“读取”。因此,您需要将这些问题分开,以使其正确。

最后,具体到您的用例,如果您直接处理MAC地址和以太网帧,Twisted包含portable behavior on platforms such as Windows,一个用于处理IP和以太网级网络的低级库。这不是Twisted中最积极维护的部分;代码很旧。但是,它应该有效,如果不成功,我们会认真对待任何错误,并(最终)看到它们得到修复。据我所知,asyncore没有类似的库,它当然不包含任何此类代码。

答案 1 :(得分:3)

Asyncore很好但功能不是很丰富,所以当你的应用程序增长时,你可能会遇到问题。话虽如此,原型设计很棒。方法很简单。您可以定义处理类中某些事件的方法(当可以读取时,可以写入时等),然后从asyncore.dispatcher(我认为)类中继承它们。

official docs for the module以及Doug Hellmann优秀的PyMOTW article on it是查看文档和示例的良好来源。

如果您的协议是会话式的(例如发送,接收),您可以查看asynchat模块,该模块也随标准库一起分发。

Twisted是一种更加繁重的方法。我相信它对于大型项目会更好,因为它使用了多少,但我不能再多说了,因为我没有任何第一手经验。

答案 2 :(得分:0)

Curl被设计为在所有视角中都是非阻塞的,并且避免使用select,这在异步I / O期间是一项代价高昂的操作。在低级别,curl正在使用最优化的可能解决方案,因此到目前为止没有框架能够比卷曲更好地执行,尽管可能存在可以提供类似性能的框架。

话虽如此,如何编写自己的套接字?它非常容易使用Python,一旦你知道自己在做什么就可以给你惊人的表现,而且你的目标很明确。