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

时间:2011-08-06 18:43:56

标签: python multithreading dictionary locking

我有一个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()

1 个答案:

答案 0 :(得分:5)

可能一些简单的锁可以解决您的问题。观察员班:

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

我最初的答案有点不完整,但我知道你有这个想法:)