2013-07-16 86 views
7

我还没有在Python中使用线程,并且把这个问题当作一个完全陌生的人。是collections.defaultdict线程安全的?

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

d = defaultdict(list) 

它创建默认情况下为丢失的钥匙列表。比方说,我有多个线程开始在同一时间做这个:

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

最后,我应该用['value', 'value']结束了。但是,如果defaultdict是不是线程安全的,如果线程1个收益率线程2检查if 'key' in dictd['key'] = default_factory()之前,就会造成交织和其他线程将在d['key']创建列表和追加'value'可能。

然后当线程1再次执行时,它会继续从d['key'] = default_factory()这将破坏现有的列表和价值,我们将在['key']结束。

我看着CPython source code for defaultdict。但是,我找不到任何锁或互斥锁。我想这是不是线程安全的,只要它被记录如此。

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

+0

https://groups.google.com/forum/#!topic/comp.lang。python/9ZnBQrYun1w可能会帮助 – 2013-07-16 16:52:40

回答

12

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

要知道为什么要明白什么时候Python的线程切换是很重要的。 CPython只允许在Python字节码步骤之间切换线程。这是GIL进来的地方;每释放一个N字节的代码指令,锁就会被释放并且可以发生线程切换。

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

defaultdict,与list作为默认值工厂配置,处理dict.__getitem__()方法完全在C,的GIL是从未解锁,使得dict[key]查找线程安全的。

注意那里的资格;如果你创建一个defaultdict实例与不同默认值工厂,一个是用Python代码(lambda: [1, 2, 3]例如),全盘皆输的,这意味着C代码回调到Python代码和GIL可以再次同时发布执行lambda函数的字节码。同样,如果工厂是用C代码编写的,可以明确释放GIL,则可以进行线程切换,并且线程安全不在窗口中。

+0

由于[显然]不是在文档中,这听起来像只是一个CPython实现细节 - 但仍然有用。 – martineau

+2

+1提到Python编写的工厂可以触发释放GIL。不幸的是,它变得更加有趣:如果对象被释放并且具有'__del__',则GIL可能触发任何'Py_DECREF'。这样,甚至纯粹的C代码也会不知不觉地导致GIL的释放 - 无可否认,它会发生病变。 – user4815162342

+2

非常有趣的是,开发人员应该了解C/Python代码执行之间的GIL版本。谢谢。 –