【发布时间】:2010-07-29 01:07:06
【问题描述】:
有人说python字典是线程安全的。这是否意味着在迭代字典时我可以或不能修改字典中的项目?
【问题讨论】:
标签: python thread-safety
有人说python字典是线程安全的。这是否意味着在迭代字典时我可以或不能修改字典中的项目?
【问题讨论】:
标签: python thread-safety
其他答案已经正确解决了您的实际问题:
这是否意味着我可以或不能修改 字典中的项目同时 迭代它?
通过解释线程安全与问题无关,并且无论如何,不,您不能在迭代时修改字典。
但是,你的问题的标题是关于线程安全的,你从以下开始:
有人说python字典是 线程安全
我不知道“某些人”是谁,但是,如果他们确实这么说(而不是你误解了他们所说的内容;-)没有严格的限定,那他们就错了。
一些操作,那些不改变字典中的键集的操作,在当前的 CPython 实现中恰好是线程安全的——但你应该不依靠这一点,除非您严格控制运行代码的 Python 版本,因为 Python 的语言规范不能保证这种线程安全,因此其他实现(包括 CPython 的未来版本)可能不会提供它。
如果每个线程都只是“读取”字典(对其进行索引、循环等),并且没有线程对其执行任何赋值或删除,那么这种情况在当前的 CPython 实现中是安全的;事实上,如果某个线程为已经存在的键分配一个新值,那也是线程安全的(其他线程可能会看到该键的前一个值或下一个值,具体取决于线程的计时方式,但在当前的 CPython 实现中不会出现崩溃、死锁和突然出现的疯狂值)。
然而,像 d[k] += 1 这样的操作(假设 k 以前存在,并且它的值是一个数字)不是正确地说是线程安全的(比 += 的其他情况更重要!)因为它可以被视为d[k] = d[k] + 1——它可能发生在竞争条件下的两个线程都读取d[k]的旧值,然后将其加一,并存储相同的新值在插槽中...所以整体效果是仅将其增加一,而不是像通常发生的那样增加二。
回到你的另一个问题......“只读取”字典,和为字典中已经存在的键分配新值,也是你可以在 a 的正文中做的事情在 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 的标准化语义保证的,因此该语言的不同实现都应该保留它。
【讨论】:
这两个概念完全不同。 Thread safety 表示两个线程不能同时修改同一个对象,从而使系统处于不一致的状态。
也就是说,您不能在迭代字典时对其进行修改。请参阅documentation.。
字典 p 不应该在迭代过程中发生变异。它是安全的(从 Python 2.1 开始) 在遍历字典时修改键的值,但只要 一组键不会改变。
【讨论】:
没有。如果您尝试迭代在两次迭代之间改变了大小的字典,最新版本的 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
请注意,您不需要使用线程来查看此内容
【讨论】:
如果您同时添加或删除另一个线程中的元素,您将无法遍历字典。你会得到“RuntimeError: dictionary changed size during iteration”或“KeyError”错误。
见live example,你就可以玩了。
是的,您可以在不同线程中同时进行迭代、更改元素的值、获取其中的元素而不会出现异常。
【讨论】: