6

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

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

鉴于对正确性的这种宽松约束,是否有一种有效的方法可以在不使用锁的情况下迭代字典?

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

4

4 回答 4

4

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

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

与 Python 2.x 中一样,在使用迭代器对其进行迭代时对 dict 进行变异具有未定义的效果,并且在大多数情况下会引发 RuntimeError 异常。(这类似于 Java 集合框架所做的保证。)

于 2012-05-15T15:27:07.607 回答
3

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

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

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

[编辑] 下面根据 JF Sebastian 的建议稍作改写:

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

我个人会选择锁。

于 2012-05-15T15:15:23.307 回答
2

两件事情:

  1. 将密钥转储到队列中并安全读取。
  2. 性能关键代码可能不应该使用 Python 线程。
于 2012-05-15T14:56:39.323 回答
1

有时,一个例子胜于言语。

数组迭代不是线程安全的,请参阅Python 3.6 的实时示例

于 2019-03-21T10:53:35.813 回答