Python: перебор словаря, в то время как другой поток изменяет словарь - PullRequest
3 голосов
/ 06 августа 2011

У меня есть окно pyglet, которое имеет атрибут «наблюдатель». У наблюдателя есть словарь «дикт». В функции main_loop () окно перерисовывает окно в соответствии с содержимым Observer.dict. Сам наблюдатель является потоком, читающим поток, добавляющим чтения к dict. Наблюдатель также имеет поток таймера, который каждую секунду проверяет наличие в dict устаревших элементов и, если это так, удаляет их.

Очевидно, что это может вызвать проблемы, если элементы добавляются или удаляются, пока окна перебирают dict. Мой текущий обходной путь - каждый раз делать глубокую копию указания и рисовать копию. Кажется, это работает, но это уродливое решение.

Я довольно новичок в python и, в частности, в w.r.t Threading / Locking / и т.д. Я думаю, мне нужен наблюдатель, чтобы "заблокировать" диктовку при добавлении или удалении элементов. Может кто-нибудь дать мне несколько советов, где искать в первую очередь?

Я пытался извлечь значимую структуру моего кода, все было бы слишком долго. Я надеюсь, что вы можете получить основную идею.

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 Ответ

5 голосов
/ 06 августа 2011

Возможно, какая-то простая блокировка может решить вашу проблему. Класс наблюдателя:

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

Мой первоначальный ответ был немного неполным, но я вижу, вы поняли:)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...