简体   繁体   English

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

[英]Python: Iterating over dictionary while another thread modifies dictionary

I have a pyglet window that has a attribute "observer". 我有一个pyglet窗口,它有一个属性“observer”。 The observer has a dictionary "dict". 观察者有一本字典“dict”。 In the main_loop() function the window re-draws the window according to the content of observer.dict. 在main_loop()函数中,窗口根据observer.dict的内容重新绘制窗口。 The observer itself is a thread reading a stream, adding readings to dict. 观察者本身是一个读取流的线程,向dict添加读数。 The observer also has a timer thread that checks each second if there are obsolete items in dict, and, if so, deletes them. 观察者还有一个计时器线程,如果dict中有过时的项目,则每秒检查一次,如果是,则删除它们。

Obviously, that might cause problems if items are added or deleted while the windows iterates over dict. 显然,如果在窗口迭代dict时添加或删除项目,则可能会导致问题。 My current workaround is to make each time a deep copy of the dict, and draw the copy. 我目前的解决方法是每次都使dict的深层副本,并绘制副本。 It seems to work, but it is a ugly solution. 它似乎有效,但它是一个丑陋的解决方案。

I'm quite new to python and particularly wrt Threading / Locking / etc. I guess I need the observer to "lock" the dict when adding or deleting items. 我对python很新,尤其是线程/锁定/等等。我想我需要观察者在添加或删除项目时“锁定”dict。 Can someone give my some hints where to look first? 有人可以给我一些提示在哪里先看?

I've tried to extract a meaningful structrue of my code, all would be too long. 我试图提取我的代码的有意义的结构,所有都会太长。 I hope you can get the main idea. 我希望你能得到主要的想法。

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()

Probably some simple lock can fix your problem. 可能一些简单的锁可以解决您的问题。 Observer class: 观察者类:

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[...]
         ...

GraphConsole class: 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():
           ...

My initial answer was a bit incomplete, but I see you got the idea :) 我的初步答案有点不完整,但我看到你有了主意:)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM