为了账号安全,请及时绑定邮箱和手机立即绑定

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

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

元芳怎么了 2021-03-16 17:33:10
查看此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而导致崩溃。但是我找不到任何可以支持上述“似乎”的东西。
查看完整描述

1 回答

?
慕的地8271018

TA贡献1796条经验 获得超4个赞

通常,只要你呼吁行动没有实现目标__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库在对象协议操作期间释放锁。那将是不寻常的事情。


查看完整回答
反对 回复 2021-03-29
  • 1 回答
  • 0 关注
  • 133 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
微信客服

购课补贴
联系客服咨询优惠详情

帮助反馈 APP下载

慕课网APP
您的移动学习伙伴

公众号

扫描二维码
关注慕课网微信公众号