假设我正在使用signal处理程序来处理间隔计时器.
def _aHandler(signum, _):
global SomeGlobalVariable
SomeGlobalVariable=True
Run Code Online (Sandbox Code Playgroud)
我可以设置SomeGlobalVariable而不必担心,在设置SomeGlobalVariable(即Python VM正在执行字节码来设置变量)的不太可能的情况下,信号处理程序中的赋值会破坏某些东西吗?(即亚稳态)
更新:我特别感兴趣的是在处理程序之外进行"复合赋值".
(也许我在想"低级别",这一切都在Python中得到了解......来自嵌入式系统的背景,我不时有这些冲动)
Ale*_*lli 21
简单的赋值简单变量是"原子"又名线程(复合赋值如+=或转让的项目或对象的属性不需要,但你的例子是一个简单的赋值给一个简单的,虽然全球性的,可变的,因此是安全的).
Google的风格指南不建议这样做
我并不是说Google样式指南是最终的真理,但“线程”部分的基本原理提供了一些见解(突出之处是我的观点):
不要依赖内置类型的原子性。
尽管Python的内置数据类型(例如字典)似乎具有原子操作,但在某些极端情况下它们不是原子操作(例如,如果将
__hash__或__eq__实现为Python方法),则不应依赖其原子性。您也不应该依赖于原子变量赋值(因为这又取决于字典)。使用
Queue模块的Queue数据类型作为线程之间通信数据的首选方式。否则,请使用线程模块及其锁定原语。了解条件变量的正确用法,以便可以使用threading.Condition而不是使用较低级别的锁。
所以我的解释是,在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
Run Code Online (Sandbox Code Playgroud)
有趣的是Martelli似乎并不介意 Google样式指南的建议:-)(他在Google工作)
我想知道CPython GIL是否对以下问题有影响:CPython 中的全局解释器锁(GIL)是什么?
该线程还表明CPython字典是线程安全的,包括以下词汇表引用,明确引用了该词汇表:https://docs.python.org/3/glossary.html#term-global-interpreter-lock
通过使对象模型(包括关键的内置类型,如dict)隐式地安全地防止并发访问,从而简化了CPython的实现。
您可以尝试dis查看底层字节码。
import dis
def foo():
a = 1
dis.dis(foo)
Run Code Online (Sandbox Code Playgroud)
产生字节码:
# a = 1
5 0 LOAD_CONST 1 (1)
2 STORE_FAST 0 (a)
Run Code Online (Sandbox Code Playgroud)
所以赋值是一个单独的 python 字节码(指令 2),它在 CPython 中是原子的,因为它一次执行一个字节码。
而添加一个a += 1:
def foo():
a = 1
a += 1
Run Code Online (Sandbox Code Playgroud)
产生字节码:
# a+=1
6 4 LOAD_FAST 0 (a)
6 LOAD_CONST 1 (1)
8 INPLACE_ADD
10 STORE_FAST 0 (a)
Run Code Online (Sandbox Code Playgroud)
+= 对应4条指令,不是原子指令。
| 归档时间: |
|
| 查看次数: |
12657 次 |
| 最近记录: |