我根本没有用Python处理过线程,而是作为一个完全陌生的人问过这个问题。
我想知道defaultdict
是否线程安全.让我解释一下:
我有过
d = defaultdict(list)
默认情况下,它会为缺少的键创建列表。假设我有多个线程同时开始执行此操作:
d['key'].append('value')
最后,我应该和['value', 'value']
一起结束。但是,如果defaultdict
不是线程安全的,如果线程1在检查if 'key' in dict
和d['key'] = default_factory()
之前向线程2输出,则会导致交织,而另一个线程可能会在d['key']
中创建列表并追加'value'
。
然后,当线程1再次执行时,它将从d['key'] = default_factory()
继续,这将销毁现有的列表和值,我们将以['key']
结束。
我看了看默认情况下的CPython源代码。然而,我找不到任何锁或互斥。我想只要它被记录下来,它就不是线程安全的。
昨晚在IRC上的一些人说Python上有GIL,所以它在概念上是线程安全的。一些人说线程不应该用Python完成。我很困惑。想法?
发布于 2013-07-16 16:54:06
在这种特殊情况下,它是线程安全的。
要了解为什么理解Python何时切换线程是很重要的。CPython只允许在Python步骤之间切换线程。这就是GIL出现的地方;锁释放的每一个N字节代码指令,都可以发生线程切换。
d['key']
代码由一个字节码(BINARY_SUBSCR
)处理,该字节码触发要在字典上调用的.__getitem__()
方法。
一个defaultdict
(配置为list
作为默认值工厂,并使用字符串值作为键)完全以C语言处理dict.__getitem__()
方法,而GIL从未被解锁,从而使dict[key]
查找线程安全。
注意这里的限定条件;如果您创建一个具有不同默认值工厂的defaultdict
实例,其中一个工厂使用lambda: [1, 2, 3]
代码(例如,lambda: [1, 2, 3]
),那么所有的赌注都取消了,因为这意味着C代码调用回lambda
代码,在执行lambda
函数的字节码时,可以再次释放GIL。这同样适用于键,当使用在Python代码中实现__hash__
或__eq__
的对象时,可以在那里发生线程切换。接下来,如果工厂是用明确释放GIL的C代码编写的,则可以发生线程切换,并且线程安全已超出窗口。
https://stackoverflow.com/questions/17682484
复制相似问题