【问题标题】:Which Python async library would be best suited for my code? Asyncore? Twisted?哪个 Python 异步库最适合我的代码?异步?扭曲?
【发布时间】:2023-03-10 00:10:01
【问题描述】:

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

我想出了一些简单的示例代码来演示我的程序将要做什么:

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,因为它是标准库的一部分。没有第 3 方依赖是奖励。但是,这并不意味着如果您建议我使用它,我就不会使用它...

我可以用 asyncore 实现我想要做的事情吗?如果是这样,你能告诉我如何将我的示例代码转换为“异步代码”吗?你知道有什么好的异步教程吗?

【问题讨论】:

    标签: python asynchronous twisted asyncore


    【解决方案1】:

    Twisted 在几乎所有可能的方面都更好。它更便携、更有特色、更简单、更具可扩展性、更好的维护、更好的文档记录,并且可以制作美味的煎蛋卷。就所有意图和目的而言,Asyncore 已经过时了。

    很难在简短的回答中展示 Twisted 的所有优势(我怎么能展示 http/dns/ssh/smtp/pop/imap/irc/xmpp/process-spawning/@ 987654327@ server 在一个简短的例子中?),所以我将重点关注人们似乎对 Twisted 最常见的误解之一:它比 asyncore 更复杂或更难使用。

    让我们从一个异步的例子开始。为了避免有偏见的介绍,我将使用仍然有点喜欢 asyncore 的其他人的示例。这是一个简单的异步示例 taken from Richard Jones' weblog(为简洁起见,省略了 cmets)。

    首先,这是服务器:

    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()
    

    我想提请您注意几件事。首先,Twisted 的例子缩短了 25%,即使是这样微不足道的东西。 asyncore 40 行,Twisted 只有 30 行。随着您的协议变得越来越复杂,这种差异会越来越大,因为您需要为 Twisted 为您提供的 asyncore 编写越来越多的支持代码。

    其次,Twisted 提供了一个完整的抽象。对于 asyncore 示例,您必须使用 socket 模块来进行实际联网; asyncore 仅提供多路复用。如果您需要portable behavior on platforms such as Windows,这是一个问题。这也意味着 asyncore 完全缺乏在其他平台上进行异步子进程通信的设施;您不能将任意文件描述符填充到 Windows 上的 select() 调用中。

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

    最后,针对您的用例,如果您直接处理 MAC 地址和以太网帧,Twisted 包含 Twisted Pair,这是一个用于处理 IP 和以太网级网络的低级库。这不是 Twisted 中维护最积极的部分。代码很旧。但是,它应该可以工作,如果没有,我们将认真对待其中的任何错误,并(最终)看到它们得到修复。据我所知,没有可比的 asyncore 库,而且它本身当然也不包含任何此类代码。

    【讨论】:

    • 这是twisted作者的精彩介绍。
    • +1。非常详细且切中要害,但我对您的期望丝毫不减。 :)
    • 绝对是一个很好的答案,更不用说它来自扭曲的首席架构师...
    • 对不起,但是一看到Python代码中的factory这个词,我就不能当真了……什么是“晦涩的案例”asyncore不能正确处理?您知道任何替代网络库(基于回调)吗?还是 Twisted 之上的 pythonic 包装器? :)
    • asyncore 无法处理的一些“晦涩”的情况是 EMFILEENOMEMaccept 返回,或 EWOULDBLOCKrecv 返回。这些只会在相当模糊的条件下发生(cmets 的长度限制会阻止我完全描述它们),但 Twisted 会默默地处理它们,asyncore 将使其主循环崩溃。
    【解决方案2】:

    Asyncore 很好,但功能不是很丰富,所以当您的应用程序增长时,您可能会遇到问题。话虽如此,制作原型非常棒。方法很简单。您定义方法来处理类中的某些事件(何时可以读取,何时可以写入等),然后从 asyncore.dispatcher (我认为)类中对其进行子类化。

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

    如果您的协议是对话式的(例如,发送这个,接收那个),您可以查看与标准库一起分发的 asynchat 模块以获取想法。

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

    【讨论】:

    • asyncore/asynchat 似乎只有在直接绑定到套接字处理时才有用。在我的代码中,sniffer 处理所有套接字内容并产生结果。我想要 asyncore 做的就是运行我的 firstsecond 函数,并允许我在 sniffers 返回数据时发出回调。我该怎么做? (顺便说一句,我没有对你投反对票)
    • asyncore/asynchat 为您提供了一个围绕 select 函数调用的面向对象的包装器(这通常是所有异步事物的构建基础)。 select 对文件描述符进行操作,因此 asyncore/asynchat 也是如此。给我几分钟的时间,让我得到一些对你有用的东西。
    • 我认为 glyph 的答案比我的更完整。
    【解决方案3】:

    Curl 被设计为在所有方面都是非阻塞的,并避免使用 select,这是在异步 I/O 期间成本高昂的操作。在低级别,curl 正在使用最优化的可能解决方案,因此迄今为止没有任何框架能够比 curl 执行得更好,尽管可能有框架可以提供类似的性能。

    话虽如此,编写自己的套接字怎么样?它在 Python 中非常简单,一旦您知道自己在做什么并且清楚自己的目标,就可以为您提供惊人的性能。

    【讨论】:

      猜你喜欢
      • 2016-04-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-08-20
      相关资源
      最近更新 更多