单例模式

单例模式

1 单例模式简介

  1. 一个类是一个类只有单个对象被创建,只能有一个实例;
  2. 自己创建这个实例;
  3. 整个系统都要使用这个实例。

1.1 为什么需要单例模式

对于有一些对象,其实例我们只需要一个,比方说:线程池、缓存(cache)、日志对象等,如果创建多个实例,就会导致许多问题产生,比如资源使用过量、程序行为不可控,或者导致不一致的结果。如:产生了很多实例,而它们做的事情只是执行发一个邮件的功能。这会特别浪费内存资源,因为频繁创建和销毁实例。

单例追求的目标:

  1. 线程安全。
  2. 懒加载:延迟加载 (懒加载)是一种将资源标识为非阻塞(非关键)资源并仅在需要时加载它们的策略。 。
  3. 调用效率高。

1.2 单例模式的基本构造

  • 私有的构造方法
  • 私有的、静态的实例化变量应用
  • 提供一个公有的、静态的获取类实例对象方法

2 代码层面理解单例模式

2.1 多例模式

  • 多例模式是一个类可以有多个对象被创建
# 多例模式
class Singleon1():
    def __init__(self, name):
        self.name = name


sin01 = Singleon1("xxx")
sin02 = Singleon1("xxx")
print(sin01)
# <__main__.Singleon1 object at 0x000001FAD4DD3DF0>
print(sin02)
# <__main__.Singleon1 object at 0x000001FAD4B62EF0>

2.2 单例模式创建

2.2.1 正常情况下的单例模式

# 单例模式
class Singleon1(object):
    instance = None  # 静态字段、类变量

    def __new__(cls, *args, **kwargs):  # cls指代当前类
        """
        创建对象
        __new__方法一定要返回一个实例对象,才会执行后面的__init__方法;
        在类的继承中,__init__方法里,我们通常写的是super(类名,self),而这里是super(类名,cls),从self变成cls的原因是,要调用父类的__new__方法,这时还没有对象实例产生。
        :param args:
        :param kwargs:
        """
        if not cls.instance:
            # cls.instance = object.__new__(cls)  # 默认调用父类的__new__()方法来创建实例,python中所有的类都继承object
            # cls.instance = super().__new__(cls)  # super().__new__(cls) super()方法返回的即是object对象
            cls.instance = super(Singleon1, cls).__new__(cls)  # super实际传入了两个参数,第一个是本类的类型(Singleon1),第二个是类型(cls),cls即父类的类
            # cls.instance = Singleon1.__new__(cls)  # 不可调用自身的__new__方法,这样会因为执行自己的__new__()方法,造成死循环,
        return cls.instance

    def __init__(self, name):
        """
        初始化对象
        :param name:
        """
        self.name = name


sin01 = Singleon1("xxx")
sin02 = Singleon1("xxx")
print(sin01)
# <__main__.Singleon1 object at 0x000001B4524F7C40>
print(sin02)
# <__main__.Singleon1 object at 0x000001B4524F7C40>

2.2.2 threading与time下的的单例模式

  • 如果直接threading直接调用单例,产生异常。

    import threading
    import time
    
    
    # 单例模式
    class Singleon1(object):
        instance = None  # 静态字段、类变量
    
        def __new__(cls, *args, **kwargs):  # cls指代当前类
            """
            创建对象
            __new__方法一定要返回一个实例对象,才会执行后面的__init__方法;
            在类的继承中,__init__方法里,我们通常写的是super(类名,self),而这里是super(类名,cls),从self变成cls的原因是,要调用父类的__new__方法,这时还没有对象实例产生。
            :param args:
            :param kwargs:
            """
            if not cls.instance:
                time.sleep(1)
                # cls.instance = object.__new__(cls)  # 默认调用父类的__new__()方法来创建实例,python中所有的类都继承object
                # cls.instance = super().__new__(cls)  # super().__new__(cls) super()方法返回的即是object对象
                cls.instance = super(Singleon1, cls).__new__(cls)  # super实际传入了两个参数,第一个是本类的类型(Singleon1),第二个是类型(cls),cls即父类的类
                # cls.instance = Singleon1.__new__(cls)  # 不可调用自身的__new__方法,这样会因为执行自己的__new__()方法,造成死循环,
            return cls.instance
    
        def __init__(self, name):
            """
            初始化对象
            :param name:
            """
            self.name = name
    
    
    def func():
        obj = Singleon1("xxx")
        print(obj)
    
    for i in range(10):
        task = threading.Thread(target=func)
        task.start()
    
    # <__main__.Singleon1 object at 0x0000017B7E5A2170>
    # <__main__.Singleon1 object at 0x0000017B7E7A3460>
    # <__main__.Singleon1 object at 0x0000017B7E5A2170>
    # <__main__.Singleon1 object at 0x0000017B7E7A3B20>
    # <__main__.Singleon1 object at 0x0000017B7E7A3EE0>
    # <__main__.Singleon1 object at 0x0000017B7E5A2170>
    # <__main__.Singleon1 object at 0x0000017B7E7A3B20>
    # <__main__.Singleon1 object at 0x0000017B7E7E9B40>
    # <__main__.Singleon1 object at 0x0000017B7E5A2170>
    # <__main__.Singleon1 object at 0x0000017B7E7A3460>
    
  • 需要对使用单例模式的类进行加锁

    import threading
    import time
    
    
    # 单例模式
    class Singleon1(object):
        instance = None  # 静态字段、类变量
        rlock = threading.RLock()
    
        def __new__(cls, *args, **kwargs):  # cls指代当前类
            """
            创建对象
            __new__方法一定要返回一个实例对象,才会执行后面的__init__方法;
            在类的继承中,__init__方法里,我们通常写的是super(类名,self),而这里是super(类名,cls),从self变成cls的原因是,要调用父类的__new__方法,这时还没有对象实例产生。
            :param args:
            :param kwargs:
            """
            if cls.instance:
                return cls.instance
            with cls.rlock:
                if not cls.instance:
                    time.sleep(1)
                    cls.instance = object.__new__(cls)  # 默认调用父类的__new__()方法来创建实例,python中所有的类都继承object
                    # cls.instance = super().__new__(cls)  # super().__new__(cls) super()方法返回的即是object对象
                    # cls.instance = super(Singleon1, cls).__new__(cls)  # super实际传入了两个参数,第一个是本类的类型(Singleon1),第二个是类型(cls),cls即父类的类
                    # cls.instance = Singleon1.__new__(cls)  # 不可调用自身的__new__方法,这样会因为执行自己的__new__()方法,造成死循环,
                return cls.instance
    
    
        def __init__(self, name):
            """
            初始化对象
            :param name:
            """
            self.name = name
    
    
    def func():
        obj = Singleon1("xxx")
        print(obj)
    
    for i in range(10):
        task = threading.Thread(target=func)
        task.start()
    
    # <__main__.Singleon1 object at 0x0000024392DA2170>
    # <__main__.Singleon1 object at 0x0000024392DA2170>
    # <__main__.Singleon1 object at 0x0000024392DA2170>
    # <__main__.Singleon1 object at 0x0000024392DA2170>
    # <__main__.Singleon1 object at 0x0000024392DA2170>
    # <__main__.Singleon1 object at 0x0000024392DA2170>
    # <__main__.Singleon1 object at 0x0000024392DA2170>
    # <__main__.Singleon1 object at 0x0000024392DA2170>
    # <__main__.Singleon1 object at 0x0000024392DA2170>
    # <__main__.Singleon1 object at 0x0000024392DA2170>
    
  • 或使用模块引用方式

    Singleon2_test.py
    # 单例模式
    class Singleon2(object):
        pass
    
    
    obj = Singleon2()
    
    
    
    test.py
    from Singleon2_test import obj
    
    if __name__ == '__main__':
        print(obj)
        print(obj)
        print(obj)
        print(obj)
    # <Singleon2_test.Singleon2 object at 0x000002C645007C40>
    # <Singleon2_test.Singleon2 object at 0x000002C645007C40>
    # <Singleon2_test.Singleon2 object at 0x000002C645007C40>
    # <Singleon2_test.Singleon2 object at 0x000002C645007C40>
    
posted @ 2023-07-26 10:42  f_carey  阅读(4)  评论(0编辑  收藏  举报