浅谈单例模式及其应用场景(Python)
生活随笔
收集整理的這篇文章主要介紹了
浅谈单例模式及其应用场景(Python)
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
使用場景:
Python的logger就是一個單例模式,用以日志記錄
Windows的資源管理器是一個單例模式
線程池,數據庫連接池等資源池一般也用單例模式
網站計數器
從這些使用場景我們可以總結下什么情況下需要單例模式:
1. 當每個實例都會占用資源,而且實例初始化會影響性能,這個時候就可以考慮使用單例模式,它給我們帶來的好處是只有一個實例占用資源,并且只需初始化一次;
當有同步需要的時候,可以通過一個實例來進行同步控制,比如對某個共享文件(如日志文件)的控制,對計數器的同步控制等,這種情況下由于只有一個實例,所以不用擔心同步問題。
1. 模塊即單利
常見的場景即logging模塊,寫好一個日志類模塊后,并實例化一個logger, 整個項目就調用這個logger
// logging_module.py
class LoggerMgr(object):
def foo(self):
pass
mylogger = LoggerMgr()
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
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__方法)。所以需要用互斥鎖來解決這個問題。
3. 使用裝飾器來獲取單例對象
# 裝飾器(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]。
4. 使用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"
5. 線程安全單利模式
import threading
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()
6. 元編程線程安全的單利模式
import threading
class MetaSingleton(type):
_instance_lock = threading.Lock()
def __call__(cls, *args, **kwargs):
if not hasattr(cls, '_instance'):
with MetaSingleton._instance_lock:
if not hasattr(cls, '_instance'):
cls._instance = super(MetaSingleton, cls).__call__(*args, **kwargs)
return cls._instance
class Singleton(metaclass=MetaSingleton):
def __init__(self, name):
self.name = name
7. 參考文獻
Python 中的單例模式
設計模式(Python)-單例模式
高并發下線程安全的單例模式
總結
以上是生活随笔為你收集整理的浅谈单例模式及其应用场景(Python)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 中科大 计算机网络5 接入网和物理媒体
- 下一篇: java 进制转换 十进制转二,八,十六