我正在开发一个程序,该程序将同时从两个“网络源”读取数据。我想尝试一种异步方法,而不是使用线程。这让我想知道使用哪个库...
我想出了一些简单的示例代码来演示我的程序将要做什么:
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 实现我想要做的事情吗?如果是这样,你能告诉我如何将我的示例代码转换为“异步代码”吗?你知道有什么好的异步教程吗?
最佳答案
Twisted 在几乎所有可能的方面都更好。它更便携、更有特色、更简单、更具可扩展性、更好的维护、更好的文档记录,并且可以制作美味的煎蛋卷。就所有意图和目的而言,Asyncore 已经过时了。
很难在简短的回答中展示 Twisted 的所有优势(我如何在一个简短的示例中展示 http/dns/ssh/smtp/pop/imap/irc/xmpp/process-spawning/multi-threading 服务器?)将重点关注人们似乎对 Twisted 最常见的误解之一:它比 asyncore 更复杂或更难使用。
让我们从一个异步的例子开始。为了避免有偏见的介绍,我将使用仍然有点喜欢 asyncore 的其他人的示例。这是一个简单的异步示例 taken from Richard Jones' weblog(为简洁起见省略了注释)。
首先,这是服务器:
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 行。随着您的协议(protocol)变得越来越复杂,这种差异会越来越大,因为您需要为 Twisted 为您提供的 asyncore 编写越来越多的支持代码。
其次,Twisted 提供了一个完整的抽象。对于 asyncore 示例,您必须使用 socket
模块来进行实际的联网; asyncore 仅提供多路复用。如果您需要 portable behavior on platforms such as Windows ,这是一个问题。这也意味着 asyncore 完全缺乏在其他平台上进行异步子进程通信的设施;您不能将任意文件描述符填充到 Windows 上的 select()
调用中。
第三,Twisted 示例是传输中立。 Echo
和 EchoFactory
和 EchoClient
和 EchoClientFactory
都不是特定于 TCP 的。只需更改一个 connectTCP
/listenTCP
调用,您就可以将这些类变成可以通过 SSH、SSL、UNIX 套接字或管道连接的库在底部。这很重要,因为直接在您的协议(protocol)逻辑中支持诸如 TLS 之类的东西非常棘手。例如,TLS 中的“写入”将触发较低级别的“读取”。因此,您需要将这些问题分离出来以使它们正确。
最后,具体到您的用例,如果您直接处理 MAC 地址和以太网帧,Twisted 包含 Twisted Pair ,这是一个用于处理 IP 和以太网级网络的低级库。这不是 Twisted 中维护最积极的部分。代码很旧。但是,它应该可以工作,如果没有,我们将认真对待其中的任何错误,并(最终)看到它们得到修复。据我所知,没有可比的 asyncore 库,而且它本身当然也不包含任何此类代码。
关于python - 哪个 Python 异步库最适合我的代码?异步?扭曲?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4384360/