2010-12-08 123 views
18

我有一個計劃,我正在從兩個'網絡資源'同時閱讀。我想嘗試一種異步方法,而不是使用線程。這導致了我想知道用哪個庫...哪個Python異步庫最適合我的代碼? 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 loop顯然使它們阻塞。

因爲它是標準庫的一部分,所以我想使用asyncore。沒有第三方依賴是獎金。但是,這並不意味着我不會使用它,如果你推薦我做...

我可以實現我想用asyncore做什麼?如果是這樣,你能告訴我如何將我的示例代碼轉換爲「asyncore代碼」?你知道任何好的asyncore教程嗎?

回答

3

Asyncore很不錯,但功能並不豐富,所以當您的應用程序增長時,您可能會遇到問題。話雖如此,原型設計很棒。該方法非常簡單。你可以定義方法來處理類中的某些事件(如果可能,可以寫入的時候等),然後從asyncore.dispatcher(我認爲)類中繼承它。

official docs for the module以及Doug Hellmann的優秀PyMOTW article on it是檢查文檔和示例的好資源。

如果你的協議是會話式的(例如發送這個,接收那個),你可以查看asynchat模塊,這個模塊也隨標準庫一起發佈。

扭曲是一種更加沉重的方法。我相信對於大型項目來說它會更好,因爲它使用了多少,但我不能再多說了,因爲我沒有任何第一手經驗。

+0

爲什麼-1? ... – 2010-12-08 07:41:26

+0

asyncore/asynchat似乎只在直接綁定到套接字處理時纔有用。在我的代碼中,`sniffer`處理所有套接字併產生結果。我希望asyncore做的就是運行我的`first`和`second`函數,並在`sniffer`返回數據時允許我發出回調。我將如何做到這一點? (我沒有downvote你,順便說一句) – dave 2010-12-08 07:47:52

49

扭曲在幾乎每一種可能的方式都更好。它更便攜,更功能,更簡單,更具可擴展性,更好的維護,更好的記錄,並且可以製作美味的煎蛋。 Asyncore對於所有的意圖和目的都是過時的。

很難證明其扭曲的優越在很短的答案(我怎麼能證明在很短的示例http/dns/ssh/smtp/pop/imap/irc/xmpp/process-spawning/multi-threading服務器?)的所有方式,所以不是我我們將專注於人們對扭曲的一種最常見的誤解:它比異化更復雜或更難以使用。

讓我們從一個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() 

有一對夫婦的事情,我想請你注意。首先,扭曲的例子縮短了25%,即使是這樣的小事。 asyncore有40行,Twisted只有30行。隨着協議變得越來越複雜,這種差異將越來越大,因爲您需要爲Twisted提供的asyncore編寫越來越多的支持代碼。

二,扭曲提供了一個完整的抽象。使用asyncore示例,您必須使用socket模塊來執行實際的網絡連接; asyncore只提供多路複用。這是一個問題,如果你需要portable behavior on platforms such as Windows。這也意味着asyncore完全缺乏在其他平臺上進行異步子進程通信的設施;您無法將任意文件描述符填入Windows上的select()調用中。

三,扭曲的例子是運輸中立EchoEchoFactoryEchoClientEchoClientFactory都不是特定於TCP的。只有通過更改底部的一個呼叫,才能將這些類創建爲可通過SSH,SSL或UNIX套接字或管道連接的庫。這很重要,因爲直接在協議邏輯中支持像TLS這樣的技術非常棘手。例如,TL​​S中的「寫入」將觸發較低級別的「讀取」。所以,你需要將這些擔憂分開來讓它們正確。

最後,針對您的使用案例,如果您直接處理MAC地址和以太網幀,Twisted包含用於處理IP和以太網網絡的低級庫Twisted Pair。這不是Twisted最主要的維護部分;代碼是相當古老的。但是,它應該起作用,如果不行,我們會嚴肅對待任何錯誤,並且(最終)看到它們得到修復。據我所知,沒有可比較的庫asyncore,它當然不包含任何這樣的代碼本身。

0

Curl被設計成在所有視角下都是非阻塞的,並避免使用select,這是異步I/O期間的昂貴操作。在低層次上,curl使用了最優化的可能解決方案,因此到目前爲止沒有框架能夠比curl更好地執行,儘管可能會有框架可以提供類似的性能。

這就是說,如何編寫自己的套接字?它非常容易使用Python,一旦你知道自己在做什麼,並且清楚你的目標,就可以給你帶來驚人的性能。