4

私はゆっくりと、しかし確実にひねりのコツをつかんでいますが、この特定のプロジェクトにどのようにアプローチすればよいかわかりません.

Web ページのバッチ処理用のクラスを作成しようとしています。個別に処理したい Web ページが複数あるため、各 URL に対してある種のパイプラインを用意することは理にかなっています。さらに、いずれかの URL が処理される前に 1 回限りの前処理関数を呼び出したいと思います。すべての URL が処理されたら、後処理関数を呼び出したいと思います。重要なのは、この処理クラスをサブクラス化し、処理しようとしているコンテンツに基づいて特定のメソッドをオーバーライドできるようにしたいということです。すべての Web ページで同じ処理手順が必要になるわけではありません。

これが同期コードである場合、おそらくコンテキスト マネージャーを使用してこれを行います。次のコード例を検討してください。

class Pipeline(object):
    def __init__(self, urls):
        self.urls = urls  # iterable
        self.continue = False

    def __enter__(self):
        self.continue = self.preprocess()

    def __exit__(self, type, value, traceback):
        if self.continue:  # if we decided to run the batch pipeline...
            self.postprocess()

    def preprocess(self):
        # does some stuff and returns a bool

    def postprocess(self):
        # do some stuff

    def pipeline(self):
        for url in self.urls:
            try:
                # download url, do some stuff
            except:
                # recover so that other urls are not interrupted

その後、次のように使用します。

with Pipeline(list_of_urls) as p:
    p.pipeline()

これは、同期ネットワーク操作ではうまく機能しますが、Twisted では機能しません。パイプライン関数は、処理パイプラインの終了前に戻り、 を呼び出すため__exit__です。

さらに、クエリの結果に基づいて条件分岐が発生する可能性があるため、各 URL の処理を​​完全に個別に実行したいと考えています。このため、Twisted を使用するDeferredListことは望ましくありません。

一言で言えば、次のものが必要です。

  • 前処理は何よりも先に実行する必要があります
  • 次の条件に当てはまる場合、後処理を実行する必要があります。
    • 少なくとも 1 つの URL が処理を開始しました (前処理が を返しますTrue)
    • すべての URL が完了したか、例外をスローしました

Twisted でこのようなものを設定する最も健全な方法は何ですか? 私が抱えている問題は、一部のコードには非同期 IO が含まれており、一部は単純な同期ロジック (つまり、結果をメモリ内で処理する) であるため、すべてを deferred で機能させる方法がわかりません (または、すべきです)。

何かアドバイス?

4

2 に答える 2

1

元の質問のコメントに照らして、 DeferredList をMaybeDeferredと組み合わせて使用​​することをお勧めします。このため、私は後者を提案します。

私が抱えている問題は、一部のコードには非同期 IO が含まれており、一部は単純な同期ロジック (つまり、結果をメモリ内で処理する) であるため、全体を deferred で機能させる方法がわかりません (または、すべきです)。

MaybeDeferred を使用すると、実際に非同期であるかどうかにかかわらず、すべての関数呼び出しを非同期であるかのように扱うことができます。

于 2013-08-20T12:00:46.113 に答える
0

次の構造は、近い状態で私を助けます:

def Processor:
   def __init__()
      self.runned = 0
      self.hasSuccess = True
      self.preprocess()

   def launch(self, urls):
      for url in urls:
        dfrd = url.process()
        dfrd.addCallback(self.succ)
        dfrd.addErrback(self.fail)
        self.runned += 1

   def fail(self, reason):
        self.runned -= 1
        if self.runned == 0 and self.hasSuccess:
            self.postprocess()

   def succ(self, arg):   
        self.runned -= 1
        self.hasSuccess = True
        if not self.runned
            self.postprocess()
于 2013-08-21T11:59:25.190 に答える