Python:在另一个线程修改字典时迭代字典

Python:在另一个线程修改字典时迭代字典,python,multithreading,dictionary,locking,Python,Multithreading,Dictionary,Locking,我有一个pyglet窗口,它有一个属性“observer”。《观察家》有一本字典“dict”。在main_loop()函数中,窗口根据observer.dict的内容重新绘制窗口。观察者本身是一个读取流的线程,向dict添加读数。观察者还有一个计时器线程,该线程每秒检查dict中是否有过时的项,如果有,则删除它们 显然,如果在windows迭代dict时添加或删除项目,这可能会导致问题。我当前的解决方法是每次制作dict的深度副本,并绘制副本。这似乎有效,但这是一个丑陋的解决方案 我对pytho

我有一个pyglet窗口,它有一个属性“observer”。《观察家》有一本字典“dict”。在main_loop()函数中,窗口根据observer.dict的内容重新绘制窗口。观察者本身是一个读取流的线程,向dict添加读数。观察者还有一个计时器线程,该线程每秒检查dict中是否有过时的项,如果有,则删除它们

显然,如果在windows迭代dict时添加或删除项目,这可能会导致问题。我当前的解决方法是每次制作dict的深度副本,并绘制副本。这似乎有效,但这是一个丑陋的解决方案

我对python非常陌生,尤其是w.r.t线程/锁定等。我想我需要观察者在添加或删除项目时“锁定”dict。有人能给我一些建议,先看看哪里吗

我试图从我的代码中提取一个有意义的结构,这一切都太长了。我希望你能了解要点

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()
类图形控制台(window.window):
定义初始化(self,*args,**kwargs):
window.window.\uuuu初始化(self,*args,**kwargs)
def初始(自身、观察者):
self.observer=观察者
def主回路(自):
当非self.has_退出时:
...
self.draw()
def牵引(自):

dict_copy=deepcopy(self.observer.dict)#也许一些简单的锁可以解决您的问题。观察员班:

class Observer(threading.Thread):
    def __init__(self, lock):
        threading.Thread.__init__(self)
        self.dict_lock = lockthreading.RLock()
        self.dict = {}
        self.timer = Timer(1, self.delete_obsolete);
        self.timer.start()

    def run(self):
        while True:
        ...
         with self._dict_lock:
             # read a stream
             self.dict.append(<new_element>)
         ...


    def delete_obsolete(self):
         ...
         with self._dict_lock:
             del self.dict[...]
         ...

我最初的回答有点不完整,但我看你明白了:)

谢谢你的快速回复。我以为应该是这样的。不幸的是,它不起作用。这当然可能取决于我的实际代码——我必须看看这个。但是,上面的缩写代码应该能够很好地捕获结构。您可能会发现尽可能少的变异操作会有所帮助。不要从dict中删除内容(或尝试制作副本),而是创建一个过滤版本(即,一个包含所有不应删除内容的新dict-而且您不需要深入复制此BTW),然后用过滤版本替换原始版本。考虑到多读卡器或单写卡器锁定系统,只需锁定更换步骤。(当然,迭代线程中也有一个锁)我重构了我的代码:Observer不再是一个线程,而是有两个线程的属性,它们通过回调调用Observer方法向Observer.dict添加/删除项。在这两个回调函数(例如delete_ocated)以及GraphConsole.draw方法中,I'protext'通过“with self.lock”。没有(可见)效果@卡尔:我想我明白你的想法,我会调查的。尽管如此,我认为它应该以某种方式工作。无论如何,谢谢你!我想我明白了——现在希望我更好地理解了锁定的概念。我创建了一个锁,并将锁的引用分配给观察者和GraphConsole(首先,我分别为每个类创建了一个锁)。现在它似乎起作用了。对不起,对于这种新手问题!再次感谢!
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):
        with self.observer.dict_lock:
            for k, v in dict_copy.iteritems():
           ...