collections.defaultdict是线程安全的吗?

时间:2013-07-16 16:49:53

标签: python defaultdict python-collections

我根本没有在Python中使用线程,并且认为这个问题是一个完全陌生的人。

我想知道defaultdict是否是线程安全的。让我解释一下:

我有

d = defaultdict(list)

默认情况下会为缺少的密钥创建一个列表。假设我有多个线程同时开始执行此操作:

d['key'].append('value')

最后,我应该以{{1​​}}结束。但是,如果['value', 'value']不是线程安全的,那么在检查defaultdict之后和{{1}之前主题1 会产生主题2 },它将导致交错,另一个线程将在if 'key' in dict中创建列表并附加d['key'] = default_factory()

然后当主题1 再次执行时,它将从d['key']继续,这会破坏现有的列表和值,我们将以'value'结束。

我看了CPython source code for defaultdict。但是,我找不到任何锁或互斥锁。我想只要记录在案,它就不是线程安全的。

昨晚有人在IRC上表示Python上有GIL,所以它在概念上是线程安全的。有人说线程不应该在Python中完成。我很困惑。想法?

1 个答案:

答案 0 :(得分:23)

这是线程安全的,在这种特定情况下

要知道在Python切换线程时理解为什么很重要。 CPython只允许在Python字节码步骤之间切换线程。这就是GIL的用武之地;每N字节代码指令释放一次锁,并且可以进行线程切换。

d['key']代码由一个字节码(BINARY_SUBSCR)处理,触发在字典上调用.__getitem__()方法。

defaultdict,配置为list作为默认值工厂,并使用字符串值作为键,在C中完全处理dict.__getitem__()方法 ,< em>和 GIL永远不会被解锁,使dict[key]查找线程安全。

注意那里的资格;如果您使用不同的默认值工厂创建defaultdict实例,使用Python代码(例如lambda: [1, 2, 3]),所有投注都会关闭,因为这意味着C代码回调到Python代码,并且在执行lambda函数的字节码时可以再次释放GIL。这同样适用于键,当使用在Python代码中实现__hash____eq__的对象时,可以在那里进行线程切换。接下来,如果工厂是用明确释放GIL的C代码编写的,则可以进行线程切换,并且线程安全不在窗口。