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

Is Python (cpython) behavior with respect to memory barriers and atomicity etc. guaranteed?

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

这(基本上)说,由于 GIL,在 python 中,至少在 cpython 中,一切都是有效的。这是有道理的,一切都被 GIL 锁定,没有内存障碍需要担心,等等。但如果这被记录在案并由规范保证,而不是让它成为 c[=60= 的结果,我会更高兴] 恰好当前正在实施。

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

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。但我也想可靠地、“正确地”做事。是否有一些官方文件说这是可以的?比如说将值放入 dict 或附加到 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)

我想确定:

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

TLDR:CPython 保证它自己的数据结构是线程安全的,不会损坏。这并不意味着 任何 自定义数据结构或代码都是无竞争的。


GIL 的目的是保护 CPython 的数据结构免受损坏。可以相信 internal 状态是线程安全的。

global interpreter lock (Python documentation – Glossary)

The mechanism used by the CPython interpreter to assure that only one thread executes Python bytecode at a time. This simplifies the CPython implementation by making the object model (including critical built-in types such as dict) implicitly safe against concurrent access. [...]

这也意味着跨线程更改的正确可见性。

然而,这并不意味着任何孤立的语句或表达式都是原子的:几乎任何语句或表达式都可以调用多个字节码指令。因此,GIL 明确地为这些情况提供原子性。

具体来说,像x.a=bar这样的语句可以通过object.__setattr__ or the descriptor protocol调用setter来执行任意多条字节码指令。它至少执行三个字节码指令,用于 bar 查找、x 查找和 a 赋值。

因此,Python保证visibility/consistency,但不保证不会出现竞争条件。如果对象同时发生变化,则必须对其进行同步以确保正确性。