9

重く聞こえるかもしれませんが、私は架空の状況を解決しようとしています。あるオブジェクトのオブザーバーがN人いると想像してください。それぞれがオブジェクトの状態に関心があります。オブザーバーパターンを適用すると、オブザーバブルオブジェクトはオブザーバーメソッドを呼び出すオブザーバーリストを反復処理する傾向がありますnotify()|update()

ここで、特定のオブザーバーが、オブザーバブルオブジェクトの状態に関係する多くの作業を行っていると想像してください。たとえば、最後の通知が遅くなります。

したがって、すべてのオブザーバーへの通知が遅くなるのを避けるために、私たちができることの1つは、別のスレッドでオブザーバーに通知することです。それが機能するためには、各オブザーバーのスレッドが必要だと思います。これは、重労働による通知の速度低下を回避するために私たちが抱えている苦痛なオーバーヘッドです。スレッドアプローチを使用する場合に速度を落とすよりも最悪なのは、無限ループによって引き起こされるデッドスレッドです。これについては、経験豊富なプログラマーを読むのは素晴らしいことです。

  • デザインの問題に長年携わっている人々はどう思いますか?
  • これは実質的な解決策のない問題ですか?
  • それは本当に悪い考えですか?なぜ?

これは、私がテストすらしていない基本的な考え方を示し、うまくいけば明確にするための漠然とした例です。

class Observable(object):
    def __init__(self):
        self.queues = {}

    def addObserver(self, observer):
        if not observer in self.queues:
            self.queues[observer] = Queue()
            ot = ObserverThread(observer, self.queues[observer])
            ot.start()

    def removeObserver(self, observer):
        if observer in self.queues:
            self.queues[observer].put('die')
            del self.queues[observer]

    def notifyObservers(self, state):
        for queue in self.queues.values():
            queue.put(state)

class ObserverThread(Thread):
    def __init__(self, observer, queue):
        self.observer = observer
        self.queue = queue

    def run(self):
        running = True
        while running:
            state = self.queue.get()
            if state == 'die':
                running = False
            else:
                self.observer.stateChanged(state)
4

4 に答える 4

7

あなたは正しい方向に進んでいます。

各オブザーバーは、独自の入力キューと独自のメッセージ処理スレッドを所有するのが一般的です(または、より適切には、キューがスレッドを所有し、オブザーバーがキューを所有します)。アクティブオブジェクトパターンを参照してください。

ただし、いくつかの落とし穴があります。

  • オブザーバーが100人または1000人いる場合は、スレッドプールパターンを使用する必要があります。
  • イベントが処理される順序(どのオブザーバーが最初にイベントを処理するか)を制御できなくなることに注意してください。これは問題ではないか、検出が非常に難しいバグのPandoraボックスを開く可能性があります。特定のアプリケーションによって異なります。
  • 通知者の前にオブザーバーが削除される状況に対処する必要がある場合があります。これは、正しく処理するのがやや難しい場合があります。
  • 関数を呼び出す代わりに、メッセージを実装する必要があります。メモリの割り当てやオブジェクトのコピーなどが必要になる場合があるため、メッセージ生成にはより多くのリソースが必要になる場合があります。一般的なメッセージタイプのメッセージプールを実装して最適化することもできます(このようなプールをラップするメッセージファクトリを実装することもできます)。 )。
  • さらに最適化するには、(同じメッセージの多数のコピーを生成するのではなく)1つのメッセージを生成し、それをすべてのオブザーバーに送信することをお勧めします。メッセージには、参照カウントメカニズムを使用する必要がある場合があります。
于 2012-12-06T14:05:12.273 に答える
2

各オブザーバーに、その反応が重いかどうかを判断させ、重い場合は、スレッドを開始するか、タスクをスレッドプールに送信します。別のスレッドで通知を行うことは良い解決策ではありません。監視可能なオブジェクトを解放する一方で、単一スレッドでの通知のプロセッサ能力を制限します。オブザーバーを信頼しない場合は、スレッドプールを作成し、通知ごとにタスクを作成してプールに送信します。

于 2012-12-09T03:27:43.553 に答える
0

私の意見では、大量の処理を行うObservableのObserverが多数ないnotify()場合、最善の方法はObserverにメソッドを用意することです。

の使用:にフラグnotify()を設定するだけです。したがって、オブザーバースレッドが適切であると判断した場合は常に、必要な更新についてObservableにクエリを実行します。dirtyObservertrue

そして、これは側面で重い処理を必要とせず、負荷をObservable側面にシフトしますObserver

Observers今、それは彼らがいつ観察しなければならないかに依存します。

于 2012-12-06T14:01:33.390 に答える
0

@Pathaiの答えは多くの場合有効です。

1つは、データベースの変更を監視していることです。多くの点で、スナップショットだけから最終状態を再構築することはできません。特に、状態がデータベースから複雑なクエリとしてフェッチされ、スナップショットがデータベースの更新である場合はそうです。

これを実装するには、Eventオブジェクトを使用することをお勧めします。

class Observer:
    def __init__(self):
        self.event = threading.Event()

# in observer:
while self.event.wait():
    # do something
    self.event.clear()

# in observable:
observer.event.set()
于 2018-10-19T13:33:25.307 に答える