是否应该在每个单独的线程中通知观察者?

时间:2012-12-06 13:51:47

标签: multithreading observer-pattern

我知道这听起来很重,但我正试图解决一个假设的情况。想象一下,你有某个对象的 N 观察者。每个人都对对象状态感兴趣。应用Observer Pattern时, observable 对象倾向于遍历其观察者列表,调用观察者notify()|update()方法。

现在想象一下,一个特定的观察者与 observable 对象的状态有很多关系。例如,这会减慢上一次通知的速度。

因此,为了避免减慢对所有观察者的通知,我们可以做的一件事是在一个单独的线程中通知观察者。为了实现这一点,我想每个观察者都需要一个线程。这是一个痛苦的开销,我们正在努力避免因繁重工作导致的通知减慢。如果使用线程方法,最慢的是减速,是由无限循环引起的死线程。读这本经验丰富的程序员会很棒。

  • 多年设计问题的人会怎么想?
  • 这是一个没有财务解决方案的问题吗?
  • 这是一个非常糟糕的主意吗?为什么呢?

实施例

这是一个模糊的例子,以展示并希望澄清我甚至没有测试过的基本概念:

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 个答案:

答案 0 :(得分:7)

你走在正确的轨道上。

每个观察者通常拥有自己的输入队列和自己的消息处理线程(或更好:队列将拥有该线程,观察者将拥有该队列)。请参阅Active object pattern

但是有一些陷阱:

  • 如果你有100或1000名观察员,你可能需要使用thread pool pattern
  • 请注意,您将无法控制将要处理事件的顺序(哪个观察者首先处理事件)。这可能是一个非问题,或者可能会打开一个非常难以检测的Pandora盒子。这取决于您的具体应用。
  • 您可能必须处理在通知者之前删除观察者的情况。这可能有点难以正确处理。
  • 您需要实现消息而不是调用函数。消息生成可能需要更多资源,因为您可能需要分配内存,复制对象等。您甚至可能希望通过为常见消息类型实现消息池来优化(您可以选择实现包装此类池的消息工厂) )。
  • 为了进一步优化,您可能希望生成一条消息并将其发送给所有观察者(而不是生成相同消息的多个副本)。您可能需要为邮件使用一些reference counting机制。

答案 1 :(得分:2)

让每个观察者自己决定它的反应是否是重量级的,如果是,则启动一个线程,或者将任务提交给一个线程池。在单独的线程中进行通知并不是一个好的解决方案:在释放可观察对象时,它会限制单线程通知的处理器能力。如果您不信任您的观察者,则创建一个线程池,并为每个通知创建一个任务并将其提交给池。

答案 2 :(得分:0)

在我看来,如果Observable有一个大没有的Observers,它会进行繁重的处理,那么最好的办法是在Observer中使用notify()方法。 / p>

使用notify():只需将dirty中的Observer标记设置为true即可。因此,只要Observer线程找到合适的,它就会查询 Observable以获取所需的更新。

这不需要在Observable方面进行大量处理,将负载转移到Observer方。

现在,当他们必须观察时,它取决于Observers

答案 3 :(得分:0)

@Pathai的答案在很多情况下都是有效的。

一个是您正在观察数据库中的更改。在许多方面,您不能仅从快照中重构最终状态,特别是如果您的状态是作为复杂查询从数据库中获取的,并且快照是对数据库的更新。

要实现它,我建议使用一个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()