LOJ-1422 萬聖節服裝
什麼是匯流排
匯流排(Bus)是計算機各種功能部件之間傳送資訊的公共通訊幹線,它是由導線組成的傳輸線束, 按照計算機所傳輸的資訊種類,計算機的匯流排可以劃分為資料匯流排、地址匯流排和控制匯流排,分別用來傳輸資料、資料地址和控制訊號。匯流排是一種內部結構,它是cpu、記憶體、輸入、輸出裝置傳遞資訊的公用通道,主機的各個部件通過匯流排相連線,外部裝置通過相應的介面電路再與匯流排相連線,從而形成了計算機硬體系統。在計算機系統中,各個部件之間傳送資訊的公共通路叫匯流排,微型計算機是以匯流排結構來連線各個功能部件的。
現假設有如下場景:某中央處理器(CPU)通過某種協議匯流排與一個訊號燈相連,訊號燈有64種顏色可以設定,中央處理器上執行著三個執行緒,都可以對這個訊號燈進行控制,並且可以獨立設定該訊號燈的顏色。抽象掉協議細節(用打印表示),如何實現執行緒對訊號等的控制邏輯。
首先我們應該想到的是加執行緒鎖進行控制,確保訊號燈順序的安全性,但是加執行緒鎖之後很顯然加大了執行緒之間的耦合性,所以這裡我們就想到了使用單例模式。即有且只有一個例項,若之後還例項改物件的話直接取出,個人認為與緩衝機制有異曲同工之妙,程式碼實現如下:
from threading import Thread,RLock import time #這裡使用方法__new__來實現單例模式 class Singleton(object):#抽象單例 #1、 用hasattr判斷 def __new__(cls, *args, **kwargs): if not hasattr(cls, '_instance'): cls._instance = super(Singleton,cls).__new__(cls, *args, **kwargs) return cls._instance # 2、用if判斷 # _instance = None # def __new__(cls, *args, **kwargs): # if cls._instance is None: # cls._instance = super(Singleton,cls).__new__(cls, *args, **kwargs) # return cls._instance #匯流排 class Bus(Singleton): lock = RLock() def sendData(self,data): self.lock.acquire() time.sleep(3) print("Sending Signal Data...",data) self.lock.release() #執行緒物件,為更加說明單例的含義,這裡將Bus物件例項化寫在了run裡 class VisitEntity(Thread): my_bus="" name="" def getName(self): return self.name def setName(self, name): self.name=name def run(self): self.my_bus=Bus() self.my_bus.sendData(self.name) if __name__=="__main__": for i in range(3): print("Entity %d begin to run..."%i) my_entity=VisitEntity() my_entity.setName("Entity_"+str(i)) my_entity.start()
單例模式
什麼是單例模式
定義:Ensure a class has only one instance, and provide a global point of access to it.
通俗理解:保證某一個類只有一個例項,而且在全域性只有一個訪問點
為什麼要用單例模式
優點:
1、由於單例模式要求在全域性內只有一個例項,因而可以節省比較多的記憶體空間;
2、全域性只有一個接入點,可以更好地進行資料同步控制,避免多重佔用;
3、單例可長駐記憶體,減少系統開銷。
缺點:
1、單例模式的擴充套件是比較困難的;
2、賦於了單例以太多的職責,某種程度上違反單一職責原則(六大原則後面會講到);
3、單例模式是併發協作軟體模組中需要最先完成的,因而其不利於測試;
4、單例模式在某種情況下會導致“資源瓶頸”
應用:
1、生成全域性惟一的序列號;
2、訪問全域性複用的惟一資源,如磁碟、匯流排等;
3、單個物件佔用的資源過多,如資料庫等;
4、系統全域性統一管理,如Windows下的Task Manager;
5、網站計數器。
實現單例模式的幾種方式
通過模組來實現
Python 的模組就是天然的單例模式,因為模組在第一次匯入時,會生成 .pyc
檔案,當第二次匯入時,就會直接載入 .pyc
檔案,而不會再次執行模組程式碼。因此,我們只需把相關的函式和資料定義在一個模組中,就可以獲得一個單例物件了。
通過類方法實現單例模式
class Mysql:
__instance = None
def __init__(self,ip,port):
self.ip = ip
self.port = port
@classmethod
def singleton(cls):
if cls.__instance:
return cls.__instance
cls.__instance = cls('127.0.0.1',8080)
return cls.__instance
obj1 = Mysql('111,111,111,0',8080)
obj2 = Mysql('222,222,222,0',8080)
print(obj1)
print(obj2)
obj3 = Mysql.singleton()
obj4 = Mysql.singleton()
print(obj3,obj4)
通過元類實現單例模式
class Mymeta(type):
def __init__(self,class_name,class_bases,class_dict):
self.__instance = object.__new__(self)
self.__init__(self.__instance,'127.0.0.1',8080)
def __call__(self, *args, **kwargs):
if args or kwargs:
obj = object.__new__(self)
self.__init__(obj,*args,**kwargs)
return obj
else:return self.__instance
class Mysql(metaclass=Mymeta):
def __init__(self,ip,port):
self.ip = ip
self.port = port
obj1 = Mysql("1.1.1.1", 3306)
obj2 = Mysql("1.1.1.2", 3306)
print(obj1)
print(obj2)
obj3 = Mysql()
obj4 = Mysql()
print(obj3 is obj4)
通過裝飾器實現單例模式
def single_func(func):
_instance = func('127.0.0.1',8080)
def inner(*args,**kwargs):
if args or kwargs:
res = func(*args,**kwargs)
return res
else:
return _instance
return inner
@single_func
class Mysql:
def __init__(self,ip,port):
self.ip = ip
self.port = port
obj1 = Mysql("1.1.1.1", 3306)
obj2 = Mysql("1.1.1.2", 3306)
print(obj1)
print(obj2)
obj3 = Mysql()
obj4 = Mysql()
print(obj3 is obj4)
通過__new__
方法實現
class Mysql:
__instance=None
def __new__(cls, *args, **kwargs):
if cls.__instance is None:
obj = object.__new__(cls)
cls.__instance = obj
return cls.__instance
obj1 = Mysql()
obj2 = Mysql()
print(obj1)
print(obj2)