1. 程式人生 > >python多執行緒安全的單例模式

python多執行緒安全的單例模式

    常用的軟體設計模式有23種,單例模式便是其中的一種。那麼在面向過程的語言中,我們常常用到全域性變數。其實單例模式和全域性變數在某種意義上來說近似。譬如我們要讀取某些配置檔案,有一個專門的類來封裝好了,但是如果不用單例模式,會造成程式例項化很多配置檔案類的物件,這樣的話會造成極大的混亂。再有就是在軟體協作開發之中,向上層提供介面的時候,最好也是用單例模式。那麼總的來說,單例模式就是面向物件程式設計的一種設計模式,單例模式保證了在程式執行中該類只例項化一次,並且提供了一個全域性訪問點。

    那麼怎麼實現呢?程式碼如下:

import threading


def synchronized(func):
    func.__lock__ = threading.Lock()

    def lock_func(*args, **kwargs):
        with func.__lock__:
            return func(*args, **kwargs)

    return lock_func


class Singleton(object):
    instance = None

    @synchronized
    def __new__(cls, *args, **kwargs):
        """

        :type kwargs: object
        """
        if cls.instance is None:
            cls.instance = super().__new__(cls)
        return cls.instance

    def __init__(self, num):
        self.a = num + 5

    def printf(self):
        print(self.a)

a = Singleton(3)
print(id(a))
b = Singleton(4)
print(id(b))

     下面分析一下上段程式碼,看不懂裝飾器的去我上一篇博文去看。這裡我們先忽略裝飾器,先看類,可以看出這裡我們先定義了一個類屬性instance,接著我們重寫了父類的__new__方法,這個方法就是我們在例項化一個物件時最先呼叫的一個方法。和其他靜態語言不一樣,其他靜態語言,直接呼叫了構造方法,一般情況下初始化的程式也寫在構造方法之中。而python例項化一個物件和初始化是分開的。__new__是類方法,__init__是例項方法,也就是說,__init__是在物件已經建立完成之後,才執行。

   在python3中,呼叫父類的方法是用super()來呼叫。所以我們這裡的思路就是,還是用父類的方法去創造,但是我們要加一個判斷,就是說,當這個物件也就是類屬性並不為空的時候,我們就不在例項化,而是返回一個已經例項化的類屬性。

  那麼這裡思考一個問題,如果就這樣可以嗎,答案是可以的,但是這種不具備通用性,多執行緒的時候依然會造成例項化出幾物件。所以再做專案時,一定要考慮這種情況。所以我們這裡通過鎖來進行保護,保證多執行緒的情況下同一時刻只有一個執行緒訪問,這就保證了單例模式的安全。

   怎麼驗證呢,程式碼也有體現,id方法是內建方法,作用是列印物件的引用地址。執行結果如下:

可以看出是成功的。