單例模式,是一種經常使用的軟件設計模式。在它的核心結構中只包含一個被稱爲單例的特殊類。經過單例模式能夠保證系統中,應用該模式的類一個類只有一個實例。即一個類只有一個對象實例django
對於系統中的某些類來講,只有一個實例很重要,例如,一個系統中能夠存在多個打印任務,可是隻能有一個正在工做的任務;一個系統只能有一個窗口管理器或文件系統;一個系統只能有一個計時工具或ID(序號)生成器。如在Windows中就只能打開一個任務管理器。若是不使用機制對窗口對象進行惟一化,將彈出多個窗口,若是這些窗口顯示的內容徹底一致,則是重複對象,浪費內存資源;若是這些窗口顯示的內容不一致,則意味着在某一瞬間系統有多個狀態,與實際不符,也會給用戶帶來誤解,不知道哪個纔是真實的狀態。所以有時確保系統中某個對象的惟一性即一個類只能有一個實例很是重要。設計模式
1.文件導入多線程
文件導入實現單例模式的方式,主要是在一個py文件中建立要單例的類,而後實例化該類,獲得該類的對象。之後調用的時候用文件導入的方式導入該對象,直接用對象.方法,不管使用該對象多少次,都只有一個實例對象在運行,即實現單例模式。ide
參考:django的admin和本身寫的stark的site工具
2.類的方式實現(加鎖是爲了支持多線程)spa
# # 單例模式:支持多線程狀況 import time import threading class Singleton(object): #建立鎖,爲多線程 _instance_lock = threading.Lock() def __init__(self): time.sleep(1)#模擬多線程阻塞 @classmethod def instance(cls, *args, **kwargs): # 判斷進程,若省略這步直接加鎖的話會使得每一個進程來時不管實例化與否都加鎖才驗證,會形成延遲 if not hasattr(Singleton, "_instance"): with Singleton._instance_lock:#爲應對多線程加鎖 if not hasattr(Singleton, "_instance"):#判斷線程 Singleton._instance = Singleton(*args, **kwargs)#實例化 return Singleton._instance#獲得單例對象 def task(arg): obj = Singleton.instance() print(obj) #批量建立多線程 for i in range(10): t = threading.Thread(target=task,args=[i,]) t.start() time.sleep(20) #單進程 obj = Singleton.instance() print(obj) #該方式的弊端:使用時必須先說明之後用單例模式時得用obj = Singleton.instance() #若公司有個小白進來用obj = Singleton()的話就不是單例了
該方式的弊端:使用時必須先說明之後用單例模式時得用obj = Singleton.instance()若公司有個小白進來用obj = Singleton()的話就不是單例了線程
3.類中基於基於__new__方式實現 (加鎖是爲了支持多線程)設計
import time import threading class Singleton(object): #建立鎖,爲多線程 _instance_lock = threading.Lock() def __init__(self): pass def __new__(cls, *args, **kwargs): #實例化時就判斷 if not hasattr(Singleton, "_instance"): with Singleton._instance_lock: if not hasattr(Singleton, "_instance"): Singleton._instance = object.__new__(cls, *args, **kwargs) return Singleton._instance obj1 = Singleton() obj2 = Singleton() print(obj1,obj2) def task(arg): obj = Singleton() print(obj) for i in range(10): t = threading.Thread(target=task,args=[i,]) t.start() # 比方式2的優勢:想用實現單例模式直接用obj = Singleton()便可,不再用擔憂小白亂來了
與方式2相比的優勢:想實現單例模式直接用obj = Singleton()便可,不再用擔憂小白亂來了code
4.基於metaclass的方式實現(加鎖是爲了支持多線程)對象
import threading class SingletonType(type): _instance_lock = threading.Lock() def __call__(cls, *args, **kwargs): if not hasattr(cls, "_instance"): with SingletonType._instance_lock: if not hasattr(cls, "_instance"): cls._instance = super(SingletonType,cls).__call__(*args, **kwargs) return cls._instance class Foo(metaclass=SingletonType): def __init__(self,name): self.name = name obj1 = Foo('name') obj2 = Foo('name') print(obj1,obj2) # 分析:Foo類是其元類的對象,在Foo類加括號時(實例化Foo類獲得obj)首先執行其元類的__call__方法, # 會判斷該類是否有實例,如有的話再也不建立,即完成單例模式
分析:Foo類是其元類的對象,在Foo類加括號時(實例化Foo類獲得obj)首先執行其元類的__call__方法,會判斷該類是否有實例,如有的話再也不建立,即完成單例模式
四種單例模式都有其必定的應用場景,都能支持多線程的狀況,文件導入的形式無需加鎖。通常狀況下用文件導入和__new__方式實現的狀況較多,在源碼中基於metaclass的方式實現較少。