3
我有一个pyglet窗口,它具有属性“observer”。观察员有字典“字典”。在main_loop()函数中,窗口根据observer.dict的内容重新绘制窗口。观察者本身是一个读取流的线程,将读数添加到字典中。观察者还有一个计时器线程,用于检查每一秒是否在dict中有过时的项目,如果是,则删除它们。Python:迭代字典,而另一个线程修改字典
显然,如果在窗口迭代字典时添加或删除项目,可能会导致问题。我目前的解决方法是让每次都是字典的深层副本,并绘制副本。它似乎工作,但它是一个丑陋的解决方案。
我对python很陌生,特别是w.r.t线程/锁定/等等。我想我需要观察者在添加或删除项目时“锁定”字典。有人能给我一些提示,首先看什么?
我试图提取一个有意义的结构,我的代码都会太长。我希望你能得到主要想法。
class GraphConsole(window.Window):
def __init__(self, *args, **kwargs):
window.Window.__init__(self, *args, **kwargs)
def init(self, observer):
self.observer = observer
def main_loop(self):
while not self.has_exit:
...
self.draw()
def draw(self):
dict_copy = deepcopy(self.observer.dict) # <-- UGLY WORKAROUND
for k, v in dict_copy.iteritems():
...
class Observer(threading.Thread):
def __init__(self):
threading.Thread.__init__(self)
self.dict = {}
self.timer = Timer(1, self.delete_obsolete);
self.timer.start()
def run(self):
while True:
...
# read a stream
self.dict.append(<new_element>)
...
def delete_obsolete(self):
...
del self.dict[...]
...
class Timer(threading.Thread):
def __init__(self, interval_in_seconds, func):
threading.Thread.__init__(self)
self.interval_in_seconds = interval_in_seconds
self.func = func
def run(self):
while True:
self.func();
time.sleep(self.interval_in_seconds)
if __name__ == "__main__":
observer = Observer();
observer.start()
graph_console = GraphConsole()
graph_console.init(observer)
graph_console.main_loop()
感谢您的快速回复。我认为它应该看起来像这样。不幸的是,它并没有做到这一点。这当然取决于我的实际代码 - 我必须看看这个。但是,上面的补充代码应该很好地捕捉结构。 – Christian
你可能会发现尽可能少的变异操作会有帮助。不要从字典中删除东西(或试图制作副本),请创建一个过滤版本(即包含**不应该被删除的所有内容的新字典 - 而且您不需要深拷贝此内容顺便说一句),然后用过滤版本替换原件。鉴于多读取器或单写入器锁定系统,只有更换步骤需要锁定。 (当然在迭代线程中也有一个锁) –
我重构了我的代码:观察者不再是一个线程,但有2个线程具有通过回调调用Observer方法向/从Observer.dict添加/删除项目的属性。在两个回调函数(例如delete_obsolete)以及GraphConsole.draw方法中,我通过“with self.lock”通过“protext”。没有(可见)效果。 - @Karl:我想我已经明白你的想法了,我会研究一下。不过,我认为它应该以某种方式正常工作。不管怎么说,还是要谢谢你! – Christian