跨线程更新观察者模式(非阻塞)
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
初学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