请参阅此Singleton实现:
if not hasattr(Singleton, "_instance"):
with Singleton._instance_lock:
if not hasattr(Singleton, "_instance"):
Singleton._instance = Singleton()
return Singleton._instance 看起来"Singleton._instance =..“(类似setattr)和hasattr是原子的。或者hasattr不会因为setattr而导致崩溃。
但我找不到任何东西来支持上面的“似乎”。
发布于 2013-06-01 19:33:44
通常是,如果你调用操作的对象没有在python中实现__getattr__、__delattr__或__setattr__挂钩,那么是的,hasattr、getattr、delattr和setattr都是原子操作。
就Python线程而言,任何单个字节码都是原子操作。Python求值循环在解释操作码时获取全局解释器锁(GIL)。
您需要查看字节码以了解边界所在:
>>> def foo():
... if not hasattr(Singleton, "_instance"):
... with Singleton._instance_lock:
... if not hasattr(Singleton, "_instance"):
... Singleton._instance = Singleton()
... return Singleton._instance
...
>>> dis.dis(foo)
2 0 LOAD_GLOBAL 0 (hasattr)
3 LOAD_GLOBAL 1 (Singleton)
6 LOAD_CONST 1 ('_instance')
9 CALL_FUNCTION 2
12 POP_JUMP_IF_TRUE 64
3 15 LOAD_GLOBAL 1 (Singleton)
18 LOAD_ATTR 2 (_instance_lock)
21 SETUP_WITH 35 (to 59)
24 POP_TOP
4 25 LOAD_GLOBAL 0 (hasattr)
28 LOAD_GLOBAL 1 (Singleton)
31 LOAD_CONST 1 ('_instance')
34 CALL_FUNCTION 2
37 POP_JUMP_IF_TRUE 55
5 40 LOAD_GLOBAL 1 (Singleton)
43 CALL_FUNCTION 0
46 LOAD_GLOBAL 1 (Singleton)
49 STORE_ATTR 3 (_instance)
52 JUMP_FORWARD 0 (to 55)
>> 55 POP_BLOCK
56 LOAD_CONST 0 (None)
>> 59 WITH_CLEANUP
60 END_FINALLY
61 JUMP_FORWARD 0 (to 64)
6 >> 64 LOAD_GLOBAL 1 (Singleton)
67 LOAD_ATTR 3 (_instance)
70 RETURN_VALUE 故事并没有到此为止;hasattr使用getattr() (测试异常),它反过来可以调用Python __getattr__钩子。类似地,python操作码可能最终调用一个STORE_ATTR __setattr__挂钩实现。在这两种情况下,GIL都会再次释放。
对于默认实现(Singleton不实现这些钩子),操作是原子的,因为Python C代码处理整个操作,而不会退回到Python,从而导致计算循环(在那里,GIL可能会被释放并为另一个线程再次锁定)。
当然,您仍然可以处理在object protocol operations期间释放锁的自定义C库。这将是一件不寻常的事情。
https://stackoverflow.com/questions/16872210
复制相似问题