1. 程式人生 > 實用技巧 >LOJ-1422 萬聖節服裝

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)