web-dev-qa-db-ja.com

Python Twisted Reactorはどのように機能しますか?

最近、私はTwistedドキュメントに飛び込んできました。私が収集したものから、Twistedの機能の基礎は、「Reactor」と呼ばれるそのイベントループの結果です。 reactorは特定のイベントをリッスンし、これらのイベントを処理するように設計された登録済みのコールバック関数にディスパッチします。この本には、Reactorの機能を説明する疑似コードがいくつかありますが、それを理解するのに苦労しています。

 while True:
     timeout = time_until_next_timed_event()
     events = wait_for_events(timeout)
     events += timed_events_until(now())
     for event in events:
         event.process()

これは何を意味するのでしょうか?

22
deadlock

はっきりしない場合は、reactorと呼ばれますが物事に反応するため )。ループはどのように反応するかです。

一度に1行:

_while True:
_

実際にはありません_while True_; _while not loop.stopped_に似ています。 reactor.stop()を呼び出してループを停止すると、(いくつかのシャットダウンロジックの実行後に)ループが実際に終了します。しかし、この例では_while True_として描かれています。これは、(Twistedでよくあるように)長命のプログラムを作成している場合、プログラムがクラッシュまたは永久に実行され、終了」は実際にはオプションではありません。

_     timeout = time_until_next_timed_event()
_

この計算を少し拡張すると、次のようになります。

_def time_until_next_timed_event():
    now = time.time()
    timed_events.sort(key=lambda event: event.desired_time)
    soonest_event = timed_events[0]
    return soonest_event.desired_time - now
_

_timed_events_は、_reactor.callLater_でスケジュールされたイベントのリストです。つまり、アプリケーションがTwistedに特定の時間に実行するように要求した関数です。

_     events = wait_for_events(timeout)
_

この行は、Twistedの「魔法」の部分です。 _wait_for_events_を一般的な方法で展開することはできません。その実装は、オペレーティングシステムが必要なイベントを利用できるようにする方法に正確に依存するためです。また、オペレーティングシステムは複雑でトリッキーな野獣であることを考えると、特定の方法で拡張することはできませんが、質問への回答を十分にシンプルに保つことはできます。

この関数の意味するところは、オペレーティングシステムに尋ねるか、Pythonラッパー)を使用して、以前に1つ以上のオブジェクトが登録されているまでブロックすることです。リスニングポートや確立された接続のようですが、クリックされる可能性のあるボタンなどの可能性もあります。これは「作業準備完了」です。作業は、ソケットがネットワークから到着したときにソケットから数バイトを読み取っている可能性があります。作業はバイトを書き込んでいる可能性がありますバッファが十分に空になると、ネットワークに送信されます。新しい接続を受け入れるか、閉じた接続を破棄している可能性があります。これらの可能なイベントはそれぞれ、リアクタがオブジェクトに対して呼び出す可能性がある関数です:dataReceivedbuildProtocolresumeProducingなど、Twistedの完全なチュートリアルを実行することで学習できます。

架空の「process」メソッドを持つ架空の「イベント」オブジェクトのリストを取得したら(メソッドの正確な名前は、歴史上の事故のために、原子炉では異なります)、次に、時間の扱いに戻ります。

_     events += timed_events_until(now())
_

まず、これはeventsが抽象listクラスのEventであると想定しています。このクラスには、特定の各タイプのイベントが満たす必要があるprocessメソッドがありますでる。

この時点で、_wait_for_events_がブロックを停止したため、ループは「起こされました」。ただし、どれだけの時間が「スリープ」していたかに基づいて、実行する必要のある時限イベントの数がわかりません。何も起こらなかった場合は、完全なタイムアウトまでスリープした可能性がありますが、多くの接続がアクティブであった場合は、事実上まったくスリープしていなかった可能性があります。したがって、現在の時刻( "now()")を確認し、処理する必要があるイベントのリストに、現在またはそれ以前の_desired_time_を持つすべての時間指定イベントを追加します時間。

最後に、

_     for event in events:
         event.process()
_

これは、Twistedが実行する必要のある処理のリストを実行して実行することを意味します。実際にはもちろん、各イベントの例外を処理します。reactorの具体的な実装では、最初に実行する必要がある作業を記録するEventのようなオブジェクトを作成するのではなく、イベントハンドラーを直接呼び出すことがよくあります。しかし、概念的にはこれがまさに何が起こるかです。ここでの_event.process_は、たとえばsocket.recv()を呼び出し、次に_yourProtocol.dataReceived_を呼び出して結果を返すことを意味します。

この拡張された説明があなたがそれを理解するのに役立つことを願っています。 Twistedに取り組んで詳細を知りたい場合は、 メーリングリストに参加 して、IRCチャネルにアクセスしてください、_#twisted_はアプリケーションについて話すか、_#twisted-dev_はTwisted自体で作業します Freenode の両方で。

30
Glyph

詳しく説明します。

  • プログラムは制御を譲り、イベント待ちでスリープします。ここで最も興味深い部分はイベントだと思います。イベントは次のとおりです。外部の要求に応じて(ネットワークパケットの受信、キーボード、タイマーのクリック、別のプログラム呼び出し)、プログラムは(他のスレッドまたは特別なルーチンで)制御を受け取ります。どういうわけかwait_for_eventsでのスリープが中断されてwait_for_eventsが戻ります。

  • 制御が発生すると、イベントハンドラーはそのイベントの情報を何らかのデータ構造eventsに格納します。これは、後でeventsevent ->プロセス)。 wait_for_eventsの開始から終了までの間に1つだけでなく多くのイベントが発生する可能性があるため、すべてのイベントを処理する必要があります。 event-> process()プロシージャはカスタムであり、通常、興味深い部分、つまりユーザーのねじれたコードを呼び出す必要があります。

2
beSpark