getattr / setattr / hasattr / delattr线程安全吗?

查看此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而导致崩溃。


但是我找不到任何可以支持上述“似乎”的东西。


元芳怎么了
浏览 134回答 1
1回答

慕的地8271018

通常,只要你呼吁行动没有实现目标__getattr__,__delattr__或者__setattr__在python挂钩,那么是的,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__钩子。同样,STORE_ATTR操作码最终可能会调用python__setattr__钩子实现。在这两种情况下,GIL都会再次被释放。对于默认实现(Singleton不实现这些挂钩),操作是原子性的,因为Python C代码可处理整个操作而不会退回到Python上,因此会产生评估循环(可能释放GIL并再次锁定另一个线程)。当然,您仍然可以使用自定义C库,该C库在对象协议操作期间释放锁。那将是不寻常的事情。
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Python