淺談單利模式及其應用場景(Python)
阿新 • • 發佈:2020-02-24
python 中的單利模式
使用場景:
+ Python的logger就是一個單例模式,用以日誌記錄
+ Windows的資源管理器是一個單例模式
+ 執行緒池,資料庫連線池等資源池一般也用單例模式
+ 網站計數器
從這些使用場景我們可以總結下什麼情況下需要單例模式:
1. 當每個例項都會佔用資源,而且例項初始化會影響效能,這個時候就可以考慮使用單例模式,它給我們帶來的好處是隻有一個例項佔用資源,並且只需初始化一次; 2. 當有同步需要的時候,可以通過一個例項來進行同步控制,比如對某個共享檔案(如日誌檔案)的控制,對計數器的同步控制等,這種情況下由於只有一個例項,所以不用擔心同步問題。
- __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__方法)。所以需要用互斥鎖來解決這個問題。
- 實現執行緒安全的單例模式
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()
- 使用裝飾器來獲取單例物件
# 裝飾器(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]。
- 使用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)-單例模