首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >哪些Python操作是原子性的?

哪些Python操作是原子性的?

作者头像
企鹅号小编
发布2018-01-11 09:42:27
3.2K0
发布2018-01-11 09:42:27
举报
文章被收录于专栏:编程编程编程

与同事的一次对话使我意识到一个事实,那就是Python中相当大一部分操作都是原子的,即使像字典和类成员赋值这样的操作也是原子的。

为了完成像哈希表插入这样的操作,需要执行很多条机器语言指令,我很难想象这个操作居然是原子的。

为什么会这样?

Python FAQ提供了解释以及原子操作的完整列表,但简短的答案是:

Python字节码解释器只有在一个机器指令完成后,另一个机器指令没开始前,才会进行线程切换。

全局解释器锁(GIL)只允许一次执行一个线程。

很多操作都被转换为单个字节码指令。

使用dis包可以很容易的查看一个操作是否编译成单个字节码指令。

那么注意事项是什么? 依靠原子性而不是使用锁是否安全?

首先,上面的链接FAQ并没有说明这种行为多大程度上被认为是Python规范的一部分,还是CPython实现的情况。 它取决于GIL,所以在GIL-less Pythons(IronPython,Jython,PyPy-TM)上可能是不安全的。 在使用GIL(PyPy)的非CPython实现上安全吗? 我当然可以想象有些优化可能会使这些操作的原子性无效。

其次,即使不是绝对必要的,锁也提供了明确的线程安全保证,并且可以作为代码访问共享内存的有用说明。 如果没有锁,必须小心,因为很容易误把非原子操作假设成原子操作(postmortem 示例:Python的swap不是原子操作)。 一个明确的备注可能也是必要的,让合作者不必产生“等等,这可能需要一个锁!”的反应。

第三,因为Python允许重载如此多的内建方法,所以有些情况下这些操作不再是原子的。 Google Python风格指南建议:

不要依赖于内置类型的原子性。

虽然Python的内置数据类型(如字典)似乎具有原子操作,但是在某些情况下它们不是原子的(例如,如果将hash或eq实现为Python方法),并且不应该依赖它们的原子性。 你也不应该依赖于原子变量赋值(因为这又取决于字典)。

对于一般情况来说,遵循这个建议就够了。

在某些情况下,例如实现新的锁功能或性能至关重要时,可能仍然存在一些情况。 依靠操作的原子性有效地允许您在GIL上搭载锁定,从而降低额外锁的成本。 但是,如果锁的性能如此重要,你最好首先分析热点并寻找其他加速点。(也就是说,一般来说锁的性能不会如此重要)

那么在访问或修改共享可变状态时依赖操作的原子性是否合理呢?

简短的回答:

如果这样做,你最好有一个很好的理由。

你最好做一些彻底的研究,弄清楚其中的原理。

否则,你最好使用锁。

英文原文:http://blog.qqrs.us/blog/2016/05/01/which-python-operations-are-atomic/

译者:LJ

本文来自企鹅号 - Python程序员媒体

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文来自企鹅号 - Python程序员媒体

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档