Python变量赋值是原子的吗?

2024-06-05 23:53:03 发布

您现在位置:Python中文网/ 问答频道 /正文

假设我使用signal处理程序来处理间隔计时器。

def _aHandler(signum, _):
  global SomeGlobalVariable
  SomeGlobalVariable=True

我是否可以设置SomeGlobalVariable而不必担心,在设置SomeGlobalVariable(即Python VM正在执行字节码来设置变量)时,信号处理程序中的赋值会中断某些内容?(即亚稳态状态)

更新:我特别感兴趣的是在处理程序之外进行“复合赋值”的情况。

(也许我觉得太“低级”了,这一切都是在Python中处理的。。。来自嵌入式系统的背景,我不时会有这样的冲动)


Tags: 程序true处理程序signal间隔字节defvm
3条回答

谷歌的风格指南建议不要这样做

我并不是说Google样式指南是终极真理,但是rationale in the "Threading" section提供了一些见解(highlight是我的):

Do not rely on the atomicity of built-in types.

While Python’s built-in data types such as dictionaries appear to have atomic operations, there are corner cases where they aren’t atomic (e.g. if __hash__ or __eq__ are implemented as Python methods) and their atomicity should not be relied upon. Neither should you rely on atomic variable assignment (since this in turn depends on dictionaries).

Use the Queue module's Queue data type as the preferred way to communicate data between threads. Otherwise, use the threading module and its locking primitives. Learn about the proper use of condition variables so you can use threading.Condition instead of using lower-level locks.

所以我的解释是,在Python中,一切都像dict一样,当你在后端做a = b时,globals['a'] = b就会发生,这很糟糕,因为dict不一定是线程安全的。

但是对于单个变量,Queue并不理想,因为我们希望它只包含一个元素,而且我在stdlib中找不到一个完美的预先存在的容器来自动同步一个.set()方法。所以现在我只想:

import threading

myvar = 0
myvar_lock = threading.Lock()
with myvar_lock:
    myvar = 1
with myvar_lock:
    myvar = 2

有趣的是Martelli does not seem to mind谷歌风格的指南推荐:-)(他在谷歌工作)

我想知道CPython GIL是否对这个问题有影响:What is the global interpreter lock (GIL) in CPython?

这个线程还表明CPython dict是线程安全的,包括下面的词汇表引用,它明确提到了CPython dict https://docs.python.org/3/glossary.html#term-global-interpreter-lock

This simplifies the CPython implementation by making the object model (including critical built-in types such as dict) implicitly safe against concurrent access.

复合赋值包括三个步骤:读-更新-写。如果运行另一个线程并在读取后写入新值,但在写入前写入,则这是竞争条件。在这种情况下,一个过时的值将被更新并写回,这将删除其他线程写入的任何新值。在Python中,任何涉及单字节代码执行的内容都应该是原子的,但是复合赋值不符合这个条件。用锁。

简单变量的简单赋值是“原子”的,也就是线程安全的(复合赋值,比如+=,或者对象的项或属性的赋值不一定是原子的,但是您的示例是一个简单的,尽管是全局的,变量的简单赋值,因此是安全的)。

相关问题 更多 >