ToB企服应用市场:ToB评测及商务社交产业平台

标题: python中单例模式先容(含线程安全的单例模式) [打印本页]

作者: 大连密封材料    时间: 5 天前
标题: python中单例模式先容(含线程安全的单例模式)
理解单例模式之前,确实必要先掌握 __init__、__new__ 和 __call__ 这三个方法的作用和调用序次。如有必要,读者可跳转下方链接学习:
python中的__init__、__new__、__call__-CSDN博客

正文开始:
在Python中,单例模式(Singleton Pattern)确保一个类只有一个实例,并提供一个全局访问点。
一、利用装饰器实现单例

   原理:通过装饰器控制类的实例化过程,确保仅天生一个实例。
步骤
  1. 界说一个装饰器函数。
2. 在装饰器中管理实例的创建和返回。
  代码示例
  1. def singleton_decorator(cls):
  2.     print("装饰器执行(类定义时立即执行)")
  3.     instances = {}
  4.     def get_instance(*args, **kwargs):
  5.         print("调用 get_instance()(实例化时执行)")
  6.         if cls not in instances:        # 单例模式的关键点就在这里
  7.             print("创建新实例")
  8.             instances[cls] = cls(*args, **kwargs)
  9.         return instances[cls]
  10.     return get_instance
  11. @singleton_decorator
  12. class SingletonClass:
  13.     def __init__(self):
  14.         print("调用 __init__()")
  15.         self.data = "Singleton Data"
  16. # 测试
  17. print("开始实例化")
  18. a = SingletonClass()
  19. print("------------")
  20. b = SingletonClass()
  21. print(a is b)  # 输出:True
  22. # 装饰器执行(类定义时立即执行)
  23. # 开始实例化
  24. # 调用 get_instance()(实例化时执行)
  25. # 创建新实例
  26. # 调用 __init__()
  27. # ------------
  28. # 调用 get_instance()(实例化时执行)
  29. # True
复制代码
二、元类实现单例重写__call__

   原理:通过元类的 __call__ 方法控制实例创建流程。
步骤
  1. 界说一个元类,重写 __call__ 方法。
  2. 在元类中查抄是否已存在实例。
  代码示例
  1. class SingletonMeta(type):
  2.     _instances = {}
  3.     def __call__(cls, *args, **kwargs):
  4.         print("调用 __call__()")
  5.         if cls not in cls._instances:
  6.             cls._instances[cls] = super().__call__(*args, **kwargs)
  7.         return cls._instances[cls]
  8. class SingletonClass(metaclass=SingletonMeta):
  9.     def __init__(self):
  10.         print("调用 __init__()")
  11.         self.data = "Singleton Data"
  12. # 测试
  13. a = SingletonClass()
  14. b = SingletonClass()
  15. print(a is b)  # 输出:True
  16. # 调用 __call__()
  17. # 调用 __init__()
  18. # 调用 __call__()
  19. # True
复制代码
三、重写 __new__ 

   原理:通过重写类的 __new__ 方法,直接控制实例创建。
步骤
  1. 在类中界说类变量存储实例。
2.在 __new__ 方法中返回已有实例或创建新实例。
  代码示例
  1. class SingletonClass:
  2.     _instance = None
  3.     def __new__(cls, *args, **kwargs):
  4.         print("__new__")
  5.         if not cls._instance:
  6.             cls._instance = super().__new__(cls)
  7.         return cls._instance
  8.     def __init__(self):
  9.         print("__init__")
  10.         self.data = "Singleton Data"
  11. # 测试
  12. a = SingletonClass()
  13. b = SingletonClass()
  14. print(a is b)  # 输出:True
  15. # __new__
  16. # __init__
  17. # __new__
  18. # __init__
  19. # True
复制代码
四、线程安全的单例模式

问题:上述方法在并发环境下大概创建多个实例。
解决方案:加锁(如 threading.Lock)确保线程安全。
代码示例(元类 + 线程安全)​
  1. import threading
  2. class SingletonMeta(type):
  3.     """
  4.     单例模式的元类实现。
  5.     控制类的实例化过程,确保线程安全且唯一实例。
  6.     """
  7.     _instances = {}  # 保存所有单例类的实例(键是类,值是实例)
  8.     _lock = threading.Lock()  # 线程锁
  9.     def __call__(cls, *args, **kwargs):
  10.         # 第一次检查:避免已存在实例时不必要的加锁
  11.         if cls not in cls._instances:
  12.             # 加锁确保线程安全
  13.             with cls._lock:
  14.                 # 第二次检查:防止其他线程已创建实例
  15.                 if cls not in cls._instances:
  16.                     # 创建实例并保存
  17.                     instance = super().__call__(*args, **kwargs)
  18.                     cls._instances[cls] = instance
  19.         # 返回已存在的实例
  20.         return cls._instances[cls]
  21. class Singleton(metaclass=SingletonMeta):
  22.     """
  23.     单例类示例。
  24.     通过元类 SingletonMeta 控制实例唯一性。
  25.     """
  26.     def __init__(self):
  27.         # 初始化代码(只会执行一次)
  28.         self._data = "单例数据"
  29.         print("Singleton 初始化完成")
  30. # 测试多线程环境下的单例行为
  31. def create_singleton():
  32.     obj = Singleton()
  33.     print(id(obj))
  34. if __name__ == "__main__":
  35.     threads = []
  36.     for _ in range(5):
  37.         t = threading.Thread(target=create_singleton)
  38.         threads.append(t)
  39.         t.start()
  40.     for t in threads:
  41.         t.join()
  42. # Singleton 初始化完成
  43. # 1807031580512
  44. # 1807031580512
  45. # 1807031580512
  46. # 1807031580512
  47. # 1807031580512
复制代码


免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。




欢迎光临 ToB企服应用市场:ToB评测及商务社交产业平台 (https://dis.qidao123.com/) Powered by Discuz! X3.4