没有一个快乐的答案;—)这个答案。其中任何一个都没有保证,您可以简单地通过注意Python参考手册对原子性没有保证来确认这一点。在
在CPython中,这是一个语用学的问题。正如effbot文章中的一个删节部分所说In theory, this means an exact accounting requires an exact understanding of the PVM [Python Virtual Machine] bytecode implementation.
这是事实。CPython专家知道L += [x]是原子的,因为他们知道以下所有内容:+=编译为INPLACE_ADD字节码。在
list对象的INPLACE_ADD的实现完全是用C编写的(执行路径上没有Python代码,因此GIL不能在字节码之间释放。在
在listobject.c中,INPLACE_ADD的实现是函数list_inplace_concat(),在其执行过程中也不需要执行任何用户Python代码(如果执行了,GIL可能再次被释放)。在
这些听起来可能难以置信地难以直截了当,但对于拥有efbot的CPython内部知识的人来说(在他写那篇文章的时候),事实并非如此。事实上,鉴于知识的深度,这一切都是显而易见的;-)
因此,作为语用学的一个问题,CPython的专家们总是自由地依赖于“看起来像原子的操作应该是原子的”,这也指导了一些语言决策。例如,effbot的列表中缺少一个操作(在他写了那篇文章之后添加到语言中):x = D.pop(y) # or ...
x = D.pop(y, default)
(当时)支持添加dict.pop()的一个论据正是,显而易见的C实现将是原子的,而在使用中(当时)的替代方法是:
^{pr2}$
was不是原子的(检索和删除是通过不同的字节码完成的,因此线程可以在它们之间切换)。在
但是文档从来没有说过原子是原子的,而且永远不会。这是一种“同意的成年人”的事情:如果你有足够的专家在知情的情况下利用这一点,你不需要牵手。如果你不够专业,那么effbot文章的最后一句话适用:When in doubt, use a mutex!
出于实际需要,核心开发人员永远不会破坏CPython中efffbot示例(或D.pop()或{})的原子性。不过,其他实现根本没有义务模仿这些实用的选择。实际上,由于这些情况下的原子性依赖于CPython特定形式的字节码,再加上CPython使用只能在字节码之间释放的全局解释器锁,可能会成为其他实现模仿它们的真正痛苦。在
你永远不知道:未来的CPython版本也可能会删除GIL!我对此表示怀疑,但理论上是可能的。但如果发生这种情况,我敢打赌保留GIL的并行版本也会得到维护,因为很多代码(尤其是用C编写的扩展模块)也依赖GIL来保证线程安全。在
值得一提的是:When in doubt, use a mutex!