словарь Python является потокобезопасным? - PullRequest
24 голосов
/ 29 июля 2010

Некоторые утверждали, что словарь Python является потокобезопасным. Означает ли это, что я могу или не могу изменить элементы в словаре, перебирая его?

Ответы [ 4 ]

63 голосов
/ 29 июля 2010

Другие ответы уже правильно адресованы тем, что, по-видимому, является вашим актуальным вопросом:

Означает ли это, что я могу или не могу изменить элементы в словаре, повторяя его?

Объясняя, что безопасность потоков не имеет ничего общего с проблемой, и в любом случае, нет, вы не можете изменить dict при его итерации.

Однако заголовок вашего вопроса - это о безопасности потоков, и вы начинаете с:

Некоторые утверждают, что словарь Python является потокобезопасным

Я не знаю, кто "некоторые "есть, но, если они заявили, что (вместо того, чтобы вы неправильно поняли, что они заявили ;-) без высокой квалификации, они ошибаются.

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

Если каждый поток только «читает» диктовку (индексирует ее, делает циклна нем и т. д.), и никакой поток не выполняет какого-либо присваивания или удаления на нем, тогда эта ситуация безопасна в текущих реализациях CPython;на самом деле, если какой-то поток назначает новое значение ключу, который уже присутствовал, это также потокобезопасно (другие потоки могут видеть предыдущее значение для этого ключа или следующее, в зависимости от того, как потоки были синхронизированы,но в текущих реализациях CPython не будет ни сбоев, ни тупиков, ни появления сумасшедших значений из ниоткуда).

Однако такая операция, как d[k] += 1 (при условии, что k ранее присутствовал, и егозначение число) не правильно говоря, потокобезопасен (больше, чем другой случай +=!), потому что его можно рассматривать как d[k] = d[k] + 1 - может произойти, что двапотоки в состоянии гонки оба читают старое значение d[k], затем увеличивают его на единицу и сохраняют одно и то же новое значение в слоте ... таким образом, общий эффект заключается в увеличении его только на единицу, а не на два, так какобычно происходит.

Возвращаясь к вашему другому вопросу ... "только чтение" dict, и присваивают новые значения клавишам, которые уже существовали в dict,также то, что вы можете делать в теле цикла, который повторяется в dict - вы не можете изменить набор ключей в dict (вы не можете добавить ни один ключ, ни удалить любой ключ), но конкретную операциюдопускается установка нового значения для существующего ключа.Разрешенные операции в этом случае включают +=, что было бы проблематично в поточной ситуации.Например:

>>> d = dict.fromkeys(range(5), 0)
>>> for k in d: d[k] += 1
... 
>>> d
{0: 1, 1: 1, 2: 1, 3: 1, 4: 1}

и это поведение гарантируется стандартизированной семантикой Python, поэтому все реализации языка должны его сохранять.

28 голосов
/ 29 июля 2010

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

При этом нельзя изменять словарь, выполняя итерации по нему.См. Документацию . .

Словарь p не должен изменяться во время итерации.Безопасно (начиная с Python 2.1) изменять значения ключей при итерации по словарю, но только до тех пор, пока набор ключей не изменится.

14 голосов
/ 29 июля 2010

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

>>> d={'one':1, 'two':2}
>>> for x in d:
...    d['three']=3
...    print x
...
two
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
RuntimeError: dictionary changed size during iteration

Обратите внимание, что вам не нужно использовать темы, чтобы увидеть это

1 голос
/ 21 марта 2019

Нельзя выполнить итерацию по словарю, если вы добавляете или удаляете элементы в другом потоке одновременно.Вы можете получить ошибки «RuntimeError: словарь изменился во время итерации» или «KeyError».

См. живой пример , и вы можете играть с ним.1012 * И да, вы можете выполнять итерацию, изменять значения элементов, получать их элементы без исключений одновременно в разных потоках.

...