Форум сайта python.su
0
Добрый день, уважаемые!
Вопрос в следующем:
Есть некая переменная, словарь. К ней имеют доступ разные функции. Все работает в многопоточном режиме. Эти все функции могут добавлять в переменную данные, изменять их, но не удалять ключи. Пусть добавляют и меняют - это нормально. Но вот в один прекрасный момент, пользователь может решить - не нужен мне какой-то ключ, или вообще все данные в словаре. и жмет кнопку “Удалить.”.
Но в момент нажатия с этой переменной могут работать несколько потоков, и, соответственно, все рухнет.
Подскажите, пожалуйста, как правильно и какими методами лучше обработать данную ситуацию? Я так понимаю, что лучше всего дождаться, пока выполнятся все потоки и тогда все удалять. Но вот, не понимаю пока как это нормально реализовать. Да, и еще ж возникнуть может такое, что переменная будет нарасхват и момент, когда она освободится может долго не возникнуть.
Офлайн
186
Не переживай. Из-за GIL в один и тот же момент времени может работать только 1 поток, по этому ничего у тебя не рухнет.
Офлайн
0
Хммм. Почему же? Очень даже рухнет. Если начать перебирать элементы словаря в одном потоке, а в другом потоке удалить элементы этого словаря - итерация срочно нарушится и упадет по RuntimeError.
Можно, конечно, обрабатывать эти исключения в каждом потоке, но может есть более красивое решение.
Офлайн
186
Насколько помню RuntimeError не будет ибо данные в итерируемом объекте могут меняться во время итерации. На всякий случай итерируй копию списка.
Офлайн
253
1. Есть “красивые” решения: локи, мютексы, семафоры, потокобезопасные очереди, чистые функции… .
Вы похоже ищете царский путь но не в математику а в многопоточные приложения.
2. Не забывайте объекты питона никуда не денутся если вы их просто из словаря удалите, на то и есть счетчики ссылок.
3. Вы и в одном треде получите бяку если возьмете итератор а перед его использованием поудаляете некоторые элементы. Это проблема не многопоточности а вашего алгоритма.
Офлайн
186
> Вы и в одном треде получите бяку если возьмете итератор а перед его использованием поудаляете некоторые элементы.
Гы?
>>> s = range(10) >>> s [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] >>> for i, x in enumerate(s): del s[i+1] >>> s [0, 2, 4, 6, 8]
Офлайн
253
Гы?
a=dict([(i,i) for i in range(5)]) for i in a: a[i+100]=i+100 >>> Traceback (most recent call last): File "<editor selection>", line 2, in <module> RuntimeError: dictionary changed size during iteration
Офлайн
186
> Гы?
Это потому что вы просто не знайте толк в извращениях!
a = dict([(i,i) for i in range(5)]) for k, v in a.items(): a[k+100]=v+100
Офлайн
0
Зачем такие сложности?
a = {'a':1,'b':2}
for key in a:
del a['b']
Traceback (most recent call last):
File "<string>", line 420, in run_nodebug
File "<модуль1>", line 20, in <module>
File "<модуль1>", line 14, in main
RuntimeError: dictionary changed size during iterationdoza_andЯ знаю, что есть, но я пока не очень в этом всем силен. Я не понимаю как это применить в моей ситуации. Можно сделать Event, и ожидать его в функции удаления. При установке этого события - другим событием заблокировать выполнение всех других потоков до тех пор, пока не выполнится функция удаления. Но это пройдет, если поток один, а если несколько - это или кучу событий делать и их всех по очереди сразу ожидать, что совсем некрасиво и по-дурацки, или делать какой-то счетчик, который будет считать количество event.clear() и разрешать делать event.set() только когда все отработают, то есть счетчик обнулится. Такой вариант у меня работает. Но не нравится он мне. И не годится он в случае, когда потоки постоянно работают и могут долго не отпускать такую блокировку (если вообще отпускать)
1. Есть “красивые” решения: локи, мютексы, семафоры, потокобезопасные очереди, чистые функции… .
doza_andПока не понимаю что Вы имеете ввиду.
2. Не забывайте объекты питона никуда не денутся если вы их просто из словаря удалите, на то и есть счетчики ссылок.
Отредактировано jor77 (Май 8, 2015 23:04:28)
Офлайн
253
Не сильны учитесь. У вас простой случай. Словарик - разделяемый ресурс. Создаете лок и все операции со словарем осуществляете только после захвата этого лока. Будет тормозить, тогда и будете разбираться как быть дальше. Не исключено что данная реализация будет работать дольше чем однопоточная. Начинать лучше с продуманого технического задания. Делать приложение многопоточным только после обоснования необходимости многопоточности.
Офлайн