淺談單利模式及其應用場景(Python)

python 中的單利模式

使用場景: + Python的logger就是一個單例模式,用以日誌記錄 + Windows的資源管理器是一個單例模式 + 線程池,數據庫鏈接池等資源池通常也用單例模式 + 網站計數器html

從這些使用場景咱們能夠總結下什麼狀況下須要單例模式:python

1. 當每一個實例都會佔用資源,並且實例初始化會影響性能,這個時候就能夠考慮使用單例模式,它給咱們帶來的好處是隻有一個實例佔用資源,而且只需初始化一次;
   2. 當有同步須要的時候,能夠經過一個實例來進行同步控制,好比對某個共享文件(如日誌文件)的控制,對計數器的同步控制等,這種狀況下因爲只有一個實例,因此不用擔憂同步問題。
  1. __new__方法實現
class Singleton(object):
        __instance = None
        def __new__(cls, *args, **kwargs):
            if cls.__instance is None:
                cls.__instance = super(Singleton, cls).__new__(cls, *args, **kwargs)
                # 能夠在這裏給實力對象綁定一些固有屬性
                # cls.__instance.appkey = ""
            return cls.__instance
  • 1.1
class Singleton(object):
        def __new__(cls, *args, **kwargs):
            # 判斷是否存在類屬性_instance,_instance是類CCP的惟一對象,即單例
            if not hasattr(Singleton, "__instance"):
                cls.__instance = super(Singleton, cls).__new__(cls, *args, **kwargs)
                # cls.__instance = object.__new__(cls)
                return cls.__instance

可是以上的方法在多線程中會有線程安全問題,當有多個線程同時去初始化對象時,就極可能同時判斷__instance is None,從而進入初始化instance的代碼中(若是有__init__方法)。因此須要用互斥鎖來解決這個問題。數據庫

  1. 實現線程安全的單例模式
import threading
    try:
        from synchronize import make_synchronized
    except ImportError:
        def make_synchronized(func):
            import threading
            func.__lock__ = threading.Lock()

            # 用裝飾器實現同步鎖
            def synced_func(*args, **kwargs):
                with func.__lock__:
                    return func(*args, **kwargs)

            return synced_func


    class Singleton(object):
        __instance = None

        @make_synchronized
        def __new__(cls, *args, **kwargs):
            if not cls.__instance:
                cls.__instance = object.__new__(cls)
            return cls.__instance

        def __init__(self):
            self.blog = "blog"

    # -------------
    def worker():
        e = Singleton()
        print(id(e))


    def meta():
        e1 = Singleton()
        e2 = Singleton()
        e1.blog = 123
        print(e1.blog)
        print(e2.blog)
        print(id(e1))
        print(id(e2))


    if __name__ == "__main__":
        meta()
        tasks = [threading.Thread(target=worker) for _ in range(20)]
        for task in tasks:
            task.start()
            task.join()
  1. 使用裝飾器來獲取單例對象
# 裝飾器(decorator)能夠動態地修改一個類或函數的功能
    import functools
    def singleton(cls):
        __instance = {}
        @functools.wraps(cls)
        def getinstance(*args, **kwargs):
            if cls not in __instance:
                __instance[cls] = cls(*args, **kwargs)
            return __instance[cls]
        return getinstance

    @singleton
    class MyClass(object):
        a = 1

咱們定義了一個裝飾器 singleton,它返回了一個內部函數 getinstance,該函數會判斷某個類是否在字典 instances 中,若是不存在,則會將 cls 做爲 key,cls(*args, **kw) 做爲 value 存到 instances 中,不然,直接返回 instances[cls]。設計模式

  1. 使用metaclass元類建立單例 元類(metaclass)能夠控制類的建立過程,它主要作三件事:
    • 攔截類的建立
    • 修改類的定義
    • 返回修改後的類
class Singleton(type):
        __instances = {}
        def __call__(cls, *args, **kwargs):
            if cls not in cls.__instances:)
                cls.__instances[cls] = super(Singleton, cls).__call__(*args, **kwargs)
            return cls.__instances[cls]
    # python2寫法
    # class MyClass(object):
    #     __metaclass__ = Singleton()

    # python3寫法
    class MyClass(metaclass=Singleton):
        def __init__(self):
            self.blog = "blog"

參考:
Python 中的單例模式
設計模式(Python)-單例模式安全

原文出處:https://www.cnblogs.com/panlq/p/12355917.html多線程

相關文章
相關標籤/搜索