可以迭代一个被另一个线程修改的字典而不会引发异常吗?

时间:2012-05-15 14:52:25

标签: python multithreading

我有一个字典由一个线程更新,而在另一个线程中我想迭代它的值。通常我会使用锁,但这段代码对性能非常关键,我想尽可能避免这种情况。

我的案例的一个特点是我不关心迭代器的绝对正确性;如果它错过了在迭代开始后删除的条目,或者拾取了之后添加的条目,那很好。我只要求它不会引起任何类型的“在迭代期间更改的字典大小”异常。

鉴于对正确性的宽松约束,是否有一种有效的方法来迭代字典而不使用锁?

注意:我知道{2.}}在Python 2.x中是线程安全的,但由于该行为在3.x中发生了变化,我想避免它。

4 个答案:

答案 0 :(得分:4)

没有个人经验,但我前段时间读过这篇文章:http://www.python.org/dev/peps/pep-3106/

  

这些操作只是在线程安全的情况下,以线程不安全的方式使用它们可能会导致异常,但不会导致内部表示损坏。

     

与Python 2.x一样,在使用迭代器迭代它时改变dict具有未定义的效果,并且在大多数情况下会引发RuntimeError异常。 (这类似于Java Collections Framework所做的保证。)

答案 1 :(得分:3)

我会考虑使用一个足够长的锁来检索你想要迭代的值:

with lock:
    values = the_dict.values() # python 2
    # values = list(the_dict.values()) # python 3
for value in values:
    # do stuff

或者,您可以在没有锁定的情况下尝试它并捕获RuntimeError,如果您得到一个,请尝试再次检索这些值。

[编辑]根据J.F.塞巴斯蒂安的建议,以下略有改写:

while True:
    try:
        values = list(the_dict.values())
        break
    except RuntimeError:
        pass

我个人会带锁。

答案 2 :(得分:2)

两件事:

  1. 将密钥转储到queue并安全地阅读。
  2. 性能关键代码可能不应该使用Python线程。

答案 3 :(得分:0)

有时候一个例子胜于文字。

数组迭代不是线程安全的,请参见live example for Python 3.6