我需要对不可变对象进行同步吗?
Do I need synchronization for immutable objects?
我有一个不可变对象 (float
),它由一个线程“写入”并由另一个线程读取。我需要同步吗?
class Foo:
def __init(self):
self._bar = None
def writeAttribute(self, newValue):
self._bar = newValue
def readAttribute(self):
return self._bar
请注意,writeAttribute
和 readAttribute
是从同一实例的不同线程调用的。我的理解是 readAttribute
returns 是对旧值或新值的“参考”,但介于两者之间。
在 CPython(来自 python.org
的那个)中,全局解释器锁(“GIL”)确保一次只有一个线程在执行Python字节码。此外,线程可以在字节码之间被抢占,但不能在它们“内部”被抢占。这意味着字节码是 atomic.
这意味着每个采用单个字节码的操作都是 thread-safe 作为 GIL 的 side-effect。
考虑以下代码,dis
模块用于查看函数的字节码:
In [2]: bar = 3.14
Out[2]: 3.14
In [3]: def modify(new):
...: global bar
...: bar = new
...:
In [4]: dis.dis(modify)
3 0 LOAD_FAST 0 (new)
2 STORE_GLOBAL 0 (bar)
4 LOAD_CONST 0 (None)
6 RETURN_VALUE
为全局 bar
分配一个新值只需要一个 STORE_GLOBAL
字节码。所以这应该是 thread-safe,因为 bar
总是指向一个对象。它的价值永远是不确定的。
注意; float
对象是不可变的并不重要。该对象的引用(示例中的bar
)是可变的。这是您要保持定义和明确的参考。
其次,我建议您使用 @property 装饰器,而不是 class Foo
中的 getter/setter 方法。算是比较Pythonic.
编辑
另请参阅常见问题解答:What kinds of global value mutation are thread-safe?
编辑2
当然:如有疑问,请使用例如Lock
.
我有一个不可变对象 (float
),它由一个线程“写入”并由另一个线程读取。我需要同步吗?
class Foo:
def __init(self):
self._bar = None
def writeAttribute(self, newValue):
self._bar = newValue
def readAttribute(self):
return self._bar
请注意,writeAttribute
和 readAttribute
是从同一实例的不同线程调用的。我的理解是 readAttribute
returns 是对旧值或新值的“参考”,但介于两者之间。
在 CPython(来自 python.org
的那个)中,全局解释器锁(“GIL”)确保一次只有一个线程在执行Python字节码。此外,线程可以在字节码之间被抢占,但不能在它们“内部”被抢占。这意味着字节码是 atomic.
这意味着每个采用单个字节码的操作都是 thread-safe 作为 GIL 的 side-effect。
考虑以下代码,dis
模块用于查看函数的字节码:
In [2]: bar = 3.14
Out[2]: 3.14
In [3]: def modify(new):
...: global bar
...: bar = new
...:
In [4]: dis.dis(modify)
3 0 LOAD_FAST 0 (new)
2 STORE_GLOBAL 0 (bar)
4 LOAD_CONST 0 (None)
6 RETURN_VALUE
为全局 bar
分配一个新值只需要一个 STORE_GLOBAL
字节码。所以这应该是 thread-safe,因为 bar
总是指向一个对象。它的价值永远是不确定的。
注意; float
对象是不可变的并不重要。该对象的引用(示例中的bar
)是可变的。这是您要保持定义和明确的参考。
其次,我建议您使用 @property 装饰器,而不是 class Foo
中的 getter/setter 方法。算是比较Pythonic.
编辑
另请参阅常见问题解答:What kinds of global value mutation are thread-safe?
编辑2
当然:如有疑问,请使用例如Lock
.