检查字典是否为关键的原子操作?

时间:2012-12-29 00:54:22

标签: python

检查密钥是否在字典中 - if key in mydict - 原子操作?

如果没有,如果一个线程正在检查一个键而另一个线程正在修改字典时会不会有任何负面影响?检查线程不会修改字典,它只是根据密钥的存在而表现不同。

1 个答案:

答案 0 :(得分:4)

我认为“原子”并不是你真正感兴趣的。

如果你没有使用CPython(或者你是,但其中一个线程正在运行不在GIL下的C代码......),它绝对不是原子的,但在某些条件下它可能是安全的。

如果 使用CPython,那么in是单个字节码op(COMPARE_OP 6)意义上它是原子的,并且在可能更有用的意义上是实际的散列表查找本身肯定发生在GIL下,任何潜在的相等比较肯定会发生在一个保证存活的对象上。但它可能仍然不安全,除非在某些条件下。

首先,你在这里做的更高级别的操作本质上是活泼的。如果线程1可以在线程0调用d['foo'] = 3的同时执行del d['foo']'foo' in d,则没有正确的答案。这不是原子问题或不是 - 这里没有排序。

但是如果你在应用程序级别确实有某种显式排序,那么得到一个正确的答案,那么只有两个线程都拥有GIL才能保证得到正确的答案。而我认为这就是你要问的问题,是吗?

这在CPython中甚至是可能的 - 即使在那里,它也相当于保证当你尝试dict或{{1}时,hash中没有任何对象可以释放GIL它通常很难保证。

现在,如果另一个线程只是替换与键关联的值,而不是更改键组,该怎么办?然后一个正确的答案,它可以同时使用,只要==实现避免改变此操作的哈希表。至少在CPython的版本中,直到2010年7月29日发布的任何版本。 Alex Martelli在回答python dictionary is thread safe?时间接保证。因此,在这种受限制的情况下,您在CPython中是安全的 - 并且可能在其他实现中,但您希望在依赖它之前阅读代码。

正如评论中指出的那样,你最终可能比较查找值的关键不能保证是不可变的,所以即使其他线程没有做任何改变键组的事情,它也是仍然并非绝对保证你会得到正确的答案。 (您可能必须制作病态密钥类型才能使其失败,但它仍然是合法密钥类型。)