Python (cpython) 在内存屏障和原子性等方面的行为是否得到保证?

我想知道 Java 的“volatile”的等价物,并找到了这个答案。

相当于 Python 中的 Java volatile

这(基本上)说,由于 GIL,至少在 cpython 中,所有东西在 python 中都是有效的。这是有道理的,一切都被 GIL 锁定,没有内存障碍需要担心,等等。但如果这是由规范记录和保证的,我会更高兴,而不是让它成为 cpython 目前碰巧的方式的结果实施的。

因为,假设我希望一个线程发布数据而其他线程读取它,所以我可以选择这样的东西:

class XFaster:

    def __init__(self):

        self._x = 0


    def set_x(self, x):

        self._x = x


    def get_x(self, x):

        return self._x



class XSafer:

    def __init__(self):

        self._x = 0

        self._lock = threading.Lock()


    def set_x(self, x):

        with self._lock:

            self._x = x


    def get_x(self, x):

        with self._lock:

            return self._x

我宁愿使用XFaster甚至根本不使用 getter 和 setter。但我也想可靠地、“正确地”做事。是否有一些官方文件说这是可以的?比如说将值放入 adict或附加到 a怎么样list?


换句话说,是否有一种系统的、有记录的方法来确定我可以做什么而无需threading.Lock(无需深入挖掘dis或类似的东西)?并且最好以不会破坏未来 python 版本的方式。


关于编辑:我感谢评论中的知情讨论。但我真正想要的是一些保证以下内容的规范:


如果我执行这样的事情:


# in the beginning

x.a == foo

# then two threads start


# thread 1:

x.a = bar


# thread 2

do_something_with(x.a)

我想确定:

  • 当线程 2 读取时,x.a它读取foo或者bar

  • 如果线程 2 中的读取发生在物理上晚于线程 1 中的分配,那么它实际上读取bar

以下是一些我不想发生的事情:

  • 线程被安排在不同的处理器上,x.a=bar线程 1 的分配对线程 2 不可见

  • x.__dict__正在重新散列,因此线程 2 读取垃圾

  • ETC


慕村9548890
浏览 134回答 1
1回答

湖上湖

CPython 保证它自己的数据结构是线程安全的,不会损坏。这并不意味着任何自定义数据结构或代码都是无竞争的。GIL 的目的是保护 CPython 的数据结构免受损坏。人们可以相信内部状态是线程安全的。全局解释器锁(Python 文档 – 词汇表)CPython 解释器用于确保一次只有一个线程执行 Python 字节码的机制。这通过使对象模型(包括关键的内置类型,如 dict)对并发访问隐式安全来简化 CPython 实现。[...]这也意味着跨线程更改的正确可见性。然而,这并不意味着任何孤立的语句或表达式都是原子的:几乎任何语句或表达式都可以调用多个字节码指令。因此,GIL 明确不为这些情况提供原子性。具体来说,一条语句x.a=bar可以通过调用 setterobject.__setattr__或描述符协议来执行任意多条字节码指令。它至少执行三个字节码指令,用于bar查找、x查找和a赋值。因此,Python保证可见性/一致性,但不提供针对竞争条件的保证。如果一个对象同时发生变化,则必须对其进行同步以确保正确性。
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Python