2010-12-08 7 views
18

私は、2つの「ネットワークソース」から同時に読み込む予定のプログラムを用意しています。私は、スレッド化を使用するのではなく、非同期のアプローチを試したかったのです。私のコードに最適な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() 

は2つのsniffer方法が見える:これは

私は一種の私のプログラムをやってどうなるかを示していくつかの簡単なコード例を作ってみた...使用するライブラリ不思議に私をリードしています

def sniff_wifi(self): 

    while True: 
     yield mac_address 

while Trueループが明らかにブロックされます。

asyncoreを標準ライブラリの一部として使用したいと思います。サードパーティの依存関係はボーナスではありません。しかし、それはあなたが私がすることをお勧めする場合、私はそれを使用しないことを意味しません...

私はasyncoreで何をしようとしていることを達成することはできますか?もしそうなら、私のサンプルコードを 'asyncore code'に変換する方法を教えてください。良いasyncoreチュートリアルを知っていますか?

答えて

3

Asyncoreは機能は豊富ではありませんが、後で問題が発生する可能性があります。つまり、試作品には素晴らしいことです。このアプローチは非常に簡単です。クラス内の特定のイベントを処理するメソッド(読み込みが可能な場合、書き込みが可能な場合など)を定義し、asyncore.dispatcherクラスからサブクラス化します。

official docs for the moduleとDoug Hellmannの優れたPyMOTW article on itは、ドキュメントと例をチェックアウトするのに適しています。

あなたのプロトコルが会話型(例えば、これを送信して受信する)であれば、標準ライブラリーと一緒に配布されているasynchatモジュールもチェックできます。

ツイストは、はるかに重大なアプローチです。どのくらい使っているのかを考えれば大規模なプロジェクトではうまくいくと思いますが、私はそれを最初に経験していないので何も言えません。

+0

なぜ-1ですか? ... –

+0

asyncore/asynchatは、ソケット処理に直接結びついている場合にのみ役に立つと思われます。私のコードでは、 'sniffer'はすべてのソケットの処理を行い、結果を出力します。 asyncoreがしたいのは、私の 'first'と' second'関数を実行し、 'sniffers'がデータを返すときにコールバックを発行することだけです。どうすればいい? (私はあなたにダウンバートしませんでした、btw) – dave

+1

asyncore/asynchatは、 'select'関数呼び出し(通常はすべての非同期のものがビルドされている)の周りにオブジェクト指向のラッパーを提供します。 'select'はファイルディスクリプタで動作し、asyncore/asynchatも同様に動作します。あなたのために何かを得るために私に数分を与えてください。 –

49

ツイストは、可能な限りあらゆる点で優れています。より移植性が高く、機能が豊富で、シンプルでスケーラブルで、メンテナンス性が高く、文書化が容易で、美味しいオムレツを作ることができます。 Asyncoreは、すべての目的と目的のために、時代遅れです。

それはツイストは(私は短い例でhttp/dns/ssh/smtp/pop/imap/irc/xmpp/process-spawning/multi-threadingサーバーを発揮できるか?)短い答えに優れているすべての方法を実証するのは難しいので、代わりにI人々がTwistedについて持っているように見える最も一般的な誤解の1つに焦点を当てます。これは、asyncoreよりも幾分複雑で使いにくいものです。

まず、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行です。あなたのプロトコルがより複雑になるにつれて、Twistedによって提供されるasyncoreのサポートコードをもっと書く必要があるので、この違いはますます大きくなります。

第2に、Twistedは、完全抽象を提供します。 asyncoreの例では、実際のネットワーキングにはsocketモジュールを使用する必要があります。 asyncoreは多重化のみを提供します。これは、portable behavior on platforms such as Windowsが必要な場合に問題になります。また、asyncoreには、他のプラットフォーム上で非同期サブプロセス通信を行うための機能が完全にないことも意味します。任意のファイル記述子をWindowsのselect()呼び出しに埋め込むことはできません。

第3に、ツイストの例は、輸送ニュートラルです。 EchoEchoFactoryEchoClientEchoClientFactoryのいずれもTCPに特有のものではありません。これらのクラスは、SSHまたはSSL、UNIXソケット、またはパイプを介して接続できるライブラリにすることができます。その場合は、connectTCP/listenTCPコールを一番下に変更します。これは重要です。あなたのプロトコルロジックで直接TLSのようなものをサポートすることは非常に難しいです。たとえば、TLSの「書き込み」は、下位レベルで「読み込み」をトリガーします。だから、あなたはそれらの権利を得るためにこれらの懸念を分ける必要があります。

最後にMACアドレスとイーサネットフレームを直接処理する場合、TwistedにはIPとイーサネットレベルのネットワークを扱うための低レベルのライブラリTwisted Pairが含まれています。これは、Twistedの中で最も積極的に維持されている部分ではありません。コードはかなり古いです。しかし、それはうまくいくはずです。そうでなければ、真剣にバグを取り、最終的には修正されていることがわかります。私が知る限り、asyncoreには匹敵するライブラリはなく、確かにそのようなコード自体は含まれていません。

+5

これは、ねじれの著者からの素晴らしい紹介です。 – pyfunc

+1

+1。非常に詳細でポイントまでは、私はあなたから何も少ないと予想した。 :) –

+0

もちろん、私の答えはもはや関連していません! – pyfunc

0

Curlはすべての視点で非ブロッキングになるように設計されており、非同期I/Oでコストのかかる操作であるselectの使用を避けています。低レベルでは、カールは、同様の性能を与えることができるフレームワークがあるかもしれないが、カールよりも優れた性能を発揮したフレームワークが存在しない日付まで、最も最適な可能な解を使用している。

これは、あなた自身のソケットを書くのはどうですか?非常にPythonで簡単ですし、あなたが何をしているのかを知ったら、素晴らしいパフォーマンスを得ることができますし、あなたの目標ではっきりしています。

関連する問題