跨线程更新观察者模式(非阻塞)

Cross Thread Update Observer Pattern (non-blocking)

初学SO,有礼仪错误请见谅(有请指出!)

我正在编写 运行ning 在程序主 UI 线程上的脚本。话虽如此,我需要避免所有阻塞调用以确保用户仍然可以进行交互。我无权访问 UI 事件循环,因此在我的情况下无法使用任何繁忙的循环解决方案。

我有一个简单的后台线程,它正在与另一个应用程序通信并收集数据,并存储在一个简单的数组中以供使用。每次更新此数据时,我都需要使用数据来修改 UI (这必须在主线程中 运行 )。理想情况下,每次更新数据时,后台线程都会发出一个信号,然后在主线程中,一个监听器会处理这个信号并修改 UI。繁忙的循环不是一个选项,一切都必须基于 asyncronous/event。

我使用 threading.timer(..) 在后台 运行 连续收集数据。但是,由于此 运行 位于单独的线程中,因此需要在外部调用 UI 操作。

def _pollLoop(self): 
    if (self._isCubeControl):
        self._getNewData()
        #in a perfect world, updateUI() would be here
        self._pollThread = threading.Timer(0.1,self._pollLoop)
        self._pollThread.start()

我需要一种方法让这个 pollLoop 回调到主线程,这样我就可以更新 UI。我已经在 pollLoop 中尝试了直接回调,但是回调是 运行 在导致错误的单独线程中。

寻找一种方法将侦听器附加到数据对象,以便在更改时更新UI() 可以运行在主线程中。

感谢您提供的任何帮助!如果这很模糊,请告诉我

更新

基于@CAB 的回答,我现在正在尝试实现观察者模式。困难在于 Observable 将在派生线程中 运行 而 Observer 更新函数必须在主线程中 运行 。我已经实施了乍得肺示例 (http://www.giantflyingsaucer.com/blog/?p=5117)。

import threading

class Observable(object):

    def __init__(self):
        self.observers = []

    def register(self, observer):
        if not observer in self.observers:
            self.observers.append(observer)

    def unregister(self, observer):
        if observer in self.observers:
            self.observers.remove(observer)

    def unregister_all(self):
        if self.observers:
             del self.observers[:]

    def update_observers(self, *args, **kwargs):
        for observer in self.observers:
            observer.update(*args, **kwargs)
        thread = threading.Timer(4,self.update_observers).start()

from abc import ABCMeta, abstractmethod

class Observer(object):
    __metaclass__ = ABCMeta

    @abstractmethod
    def update(self, *args, **kwargs):
        pass

class myObserver(Observer):  
    def update(self, *args, **kwargs):
        '''update is called in the source thread context'''
        print(str(threading.current_thread()))

observable = Observable()

observer = myObserver()
observable.register(observer)

observable.update_observers('Market Rally', something='Hello World')

我得到的回复是:

<_MainThread(MainThread, started 140735179829248)>
<_Timer(Thread-1, started 123145306509312)>
<_Timer(Thread-2, started 123145310715904)>

很明显,Observer 运行在生成的线程中而不是主线程中。有人对我有另一种方法吗? :) 再一次,我不能有一个繁忙的循环来定期检查值的变化(我希望.. :( ) 这个脚本是 运行ning overtop a UI 并且我无权访问 GUI 事件循环,所以一切都需要异步和非阻塞。

让我们以 http://www.giantflyingsaucer.com/blog/?p=5117 中的示例为基础。

from abc import ABCMeta, abstractmethod

class Observer(object):
    __metaclass__ = ABCMeta

    @abstractmethod
    def update(self, *args, **kwargs):
        pass

然后 Observer 实现有责任断开线程。假设我们使用一个简单的线程来做到这一点。 (语法可能不对,我正在塞进去,需要赶公共汽车)。

from observer import Observer
from threading import Thread

class myObserver(Observer):

    def update(self, *args, **kwargs):
        '''update is called in the source thread context'''
        Thread(target=self.handler, args=(self,*args), kwargs=**kwargs).start()

    def handler(self, *args, **kwargs):
       '''handler runs in an independent thread context'''
       pass # do something useful with the args