zoukankan      html  css  js  c++  java
  • python 单例模式

    单例模式

    单例模式(Singleton Pattern)是一种常用的软件设计模式,该模式的主要目的是确保某一个类只有一个实例存在。当你希望在整个系统中,某个类只能出现一个实例时,单例对象就能派上用场。

    比如数据库连接读取配置文件,如果在程序运行期间,有很多地方都需要连接数据库,很多地方都需要创建数据库对象的实例,这就导致系统中存在多个 数据库实例对象,而这样会严重浪费内存资源,事实上,我们希望在程序运行期间只存在一个实例对象。

    实现单例模式的5种方式

    模块方式

    其实,Python 的模块就是天然的单例模式,因为模块在第一次导入时,会生成 .pyc 文件,当第二次导入时,就会直接加载 .pyc 文件,而不会再次执行模块代码。

    因此,我们只需把相关的函数和数据定义在一个模块中,就可以获得一个单例对象了。如果我们真的想要一个单例类,可以考虑这样做:

    mysingleton.py

    class Singleton(object):
        def foo(self):
            pass
    single = Singleton()
    

     将上面的代码保存在文件 mysingleton.py 中,要使用时,直接在其他文件中导入此文件中的对象,这个对象即是单例模式的对象

    from demo.my_singleton import single
    
    single.foo()
    

      

    使用装饰器

    def Singleton(cls):
        _instance = {}
    
        def _singleton(*args, **kargs):
            if cls not in _instance:
                _instance[cls] = cls(*args, **kargs)
            return _instance[cls]
    
        return _singleton
    
    
    @Singleton
    class A(object):
        def __init__(self, x=0):
            self.x = x
    
    
    a1 = A(2)
    a2 = A(3)
    
    print(id(a1), id(a2))
    

      

    使用类

    class Singleton(object):
        __instance = None
    
        def __init__(self, x):
            self.x = x
            print(x)
    
        @classmethod
        def my_singleton(cls, *args, **kwargs):
            if not cls.__instance:
                cls.__instance = cls(*args, **kwargs)
            return cls.__instance
    

    如果遇到多线程会出现问题 

    import threading
    
    
    class Singleton(object):
        __instance = None
    
        def __init__(self, x):
            self.x = x
            import time
            time.sleep(1)  # 加入干扰元素,造成多线程出现问题
    
        @classmethod
        def my_singleton(cls, *args, **kwargs):
            if not cls.__instance:
                cls.__instance = cls(*args, **kwargs)
            return cls.__instance
    
    
    import threading
    
    
    def task(arg):
        obj = Singleton.my_singleton(arg)
        print(obj)
    
    
    for i in range(10):
        t = threading.Thread(target=task, args=(i,))
        t.start()
    
    -------------------
    <__main__.Singleton object at 0x00000000025D76D8>
    <__main__.Singleton object at 0x000000000259FF28>
    <__main__.Singleton object at 0x000000001234A208>
    <__main__.Singleton object at 0x000000001234A1D0>
    <__main__.Singleton object at 0x000000001234A438>
    <__main__.Singleton object at 0x000000001234A630>
    <__main__.Singleton object at 0x000000001234A828>
    <__main__.Singleton object at 0x000000001234A978>
    <__main__.Singleton object at 0x000000001234A748>
    <__main__.Singleton object at 0x000000001234AAC8>
    

      

    解决方法:加锁!未加锁部分并发执行,加锁部分串行执行,速度降低,但是保证了数据安全

    import threading
    
    
    class Singleton(object):
        __instance = None
        __instance_lock = threading.Lock()
    
        def __init__(self, x):
            self.x = x
            import time
            time.sleep(1)  # 加入干扰元素,造成多线程出现问题
    
        @classmethod
        def my_singleton(cls, *args, **kwargs):
            with cls.__instance_lock:  # 加锁
                if not cls.__instance:
                    cls.__instance = cls(*args, **kwargs)
            return cls.__instance
    
    
    import threading
    
    
    def task(arg):
        obj = Singleton.my_singleton(arg)
        print(obj)
    
    
    for i in range(10):
        t = threading.Thread(target=task, args=(i,))
        t.start()
    
    
    ----------------------
    <__main__.Singleton object at 0x000000000259FF28>
    <__main__.Singleton object at 0x000000000259FF28>
    <__main__.Singleton object at 0x000000000259FF28>
    <__main__.Singleton object at 0x000000000259FF28>
    <__main__.Singleton object at 0x000000000259FF28>
    <__main__.Singleton object at 0x000000000259FF28>
    <__main__.Singleton object at 0x000000000259FF28>
    <__main__.Singleton object at 0x000000000259FF28>
    <__main__.Singleton object at 0x000000000259FF28>
    <__main__.Singleton object at 0x000000000259FF28>
    

      

    基于__new__方法实现(推荐使用)

    当我们实例化一个对象时,是先执行了类的__new__方法(我们没写时,默认调用object.__new__),实例化对象;然后再执行类的__init__方法,对这个对象进行初始化。

    import threading
    
    
    class Singleton(object):
        _instance_lock = threading.Lock()
    
        def __init__(self, x):
            self.x = x
            import time
            time.sleep(1)  # 加入干扰元素,造成多线程出现问题
    
        def __new__(cls, *args, **kwargs):
            if not hasattr(cls, '_instance'):
                with cls._instance_lock:  # 加锁
                    cls._instance = super(Singleton, cls).__new__(cls)
            return cls._instance
    
    
    import threading
    
    
    def task(arg):
        obj = Singleton(arg)
        print(obj)
    
    
    for i in range(10):
        t = threading.Thread(target=task, args=(i,))
        t.start()
    
    ----------------
    
    <__main__.Singleton object at 0x000000000257FF60>
    <__main__.Singleton object at 0x000000000257FF60>
    <__main__.Singleton object at 0x000000000257FF60>
    <__main__.Singleton object at 0x000000000257FF60>
    <__main__.Singleton object at 0x000000000257FF60>
    <__main__.Singleton object at 0x000000000257FF60>
    <__main__.Singleton object at 0x000000000257FF60>
    <__main__.Singleton object at 0x000000000257FF60>
    <__main__.Singleton object at 0x000000000257FF60>
    <__main__.Singleton object at 0x000000000257FF60>
    

      

    基于metaclass方式实现

    1.类由type创建,创建类时,type的__init__方法自动执行,类() 执行type的 __call__方法(类的__new__方法,类的__init__方法)
    2.对象由类创建,创建对象时,类的__init__方法自动执行,对象()执行类的 __call__ 方法
    

     实现单例

    import threading
    
    
    class SingletonType(type):
        _instance_lock = threading.Lock()
    
        def __init__(self,class_name,class_bases,class_dic):
            super(SingletonType, self).__init__(class_name,class_bases,class_dic)
    
        def __call__(cls, *args, **kwargs):
            if not hasattr(cls, '_instance'):
                with cls._instance_lock:  # 加锁
                    cls._instance = super(SingletonType, cls).__call__(*args, **kwargs)
            return cls._instance
    
    
    class my_singlton(metaclass=SingletonType):
        def __init__(self,x):
            self.x = x
    
    import threading
    
    
    def task(arg):
        obj = my_singlton(arg)
        print(obj)
    
    
    for i in range(10):
        t = threading.Thread(target=task, args=(i,))
        t.start()
    
    --------------------------
    <__main__.my_singlton object at 0x00000000025CFF60>
    <__main__.my_singlton object at 0x00000000025CFF60>
    <__main__.my_singlton object at 0x00000000025CFF60>
    <__main__.my_singlton object at 0x00000000025CFF60>
    <__main__.my_singlton object at 0x00000000025CFF60>
    <__main__.my_singlton object at 0x00000000025CFF60>
    <__main__.my_singlton object at 0x00000000025CFF60>
    <__main__.my_singlton object at 0x00000000025CFF60>
    <__main__.my_singlton object at 0x00000000025CFF60>
    <__main__.my_singlton object at 0x00000000025CFF60>
    

      

    单例模式使用

     

    import threading
    
    
    class SingletonDB(object):
        _instance_lock = threading.Lock()
    
        def __init__(self,host='127.0.0.1',
                port=3306,
                user='root',
                password='root',
                database='testdb',
                charset='utf8'):
            self.host = host
            self.port = port
            self.password = password
            self.user = user
            self.database = database
            self.charset = charset
    
        def __new__(cls, *args, **kwargs):
            if not hasattr(SingletonDB, "_instance"):
                with SingletonDB._instance_lock:
                    if not hasattr(SingletonDB, "_instance"):
                        SingletonDB._instance = object.__new__(cls, *args, **kwargs)
            return SingletonDB._instance
    
        def connect(self):
            print('connect db')
    
    
    db1 = SingletonDB()
    db2 = SingletonDB()
    
    print(db1,db2)
    db1.connect()
    db2.connect()
    
    ----------------
    <__main__.SingletonDB object at 0x00000000025E76D8> <__main__.SingletonDB object at 0x00000000025E76D8>
    connect db
    connect db
    

      

  • 相关阅读:
    Window 窗口类
    使用 Bolt 实现 GridView 表格控件
    lua的table库
    Windows编程总结之 DLL
    lua 打印 table 拷贝table
    使用 xlue 实现简单 listbox 控件
    使用 xlue 实现 tips
    extern “C”
    COleVariant如何转换为int double string cstring
    原来WIN32 API也有GetOpenFileName函数
  • 原文地址:https://www.cnblogs.com/xiao-apple36/p/9398760.html
Copyright © 2011-2022 走看看