1 回答

TA貢獻(xiàn)1796條經(jīng)驗(yàn) 獲得超4個(gè)贊
通常,只要你呼吁行動(dòng)沒(méi)有實(shí)現(xiàn)目標(biāo)__getattr__,__delattr__或者_(dá)_setattr__在python掛鉤,那么是的,hasattr,getattr,delattr和setattr是一個(gè)基本操作。
就Python線程而言,任何單個(gè)字節(jié)碼都是原子操作。Python評(píng)估循環(huán)在解釋操作碼時(shí)會(huì)抓住全局解釋器鎖(GIL)。
您需要查看字節(jié)碼以了解邊界所在的位置:
>>> 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()(測(cè)試是否有異常),而后者又可以調(diào)用Python__getattr__鉤子。同樣,STORE_ATTR操作碼最終可能會(huì)調(diào)用python__setattr__鉤子實(shí)現(xiàn)。在這兩種情況下,GIL都會(huì)再次被釋放。
對(duì)于默認(rèn)實(shí)現(xiàn)(Singleton不實(shí)現(xiàn)這些掛鉤),操作是原子性的,因?yàn)镻ython C代碼可處理整個(gè)操作而不會(huì)退回到Python上,因此會(huì)產(chǎn)生評(píng)估循環(huán)(可能釋放GIL并再次鎖定另一個(gè)線程)。
當(dāng)然,您仍然可以使用自定義C庫(kù),該C庫(kù)在對(duì)象協(xié)議操作期間釋放鎖。那將是不尋常的事情。
添加回答
舉報(bào)