单例模式
单例模式(Singleton Pattern)是一种经常使用的软件设计模式,该模式的主要目的是确保某一个类只有一个实例存在。当你但愿在整个系统中,某个类只能出现一个实例时,单例对象就能派上用场。java
好比,某个服务器程序的配置信息存放在一个文件中,客户端经过一个 AppConfig 的类来读取配置文件的信息。若是在程序运行期间,有不少地方都须要使用配置文件的内容,也就是说,不少地方都须要建立 AppConfig 对象的实例,这就致使系统中存在多个 AppConfig 的实例对象,而这样会严重浪费内存资源,尤为是在配置文件内容不少的状况下。事实上,相似 AppConfig 这样的类,咱们但愿在程序运行期间只存在一个实例对象。设计模式
在 Python 中,咱们能够用多种方法来实现单例模式安全
实现单例模式的几种方式
1.使用模块
其实,Python 的模块就是自然的单例模式,由于模块在第一次导入时,会生成 .pyc
文件,当第二次导入时,就会直接加载 .pyc
文件,而不会再次执行模块代码。所以,咱们只需把相关的函数和数据定义在一个模块中,就能够得到一个单例对象了。若是咱们真的想要一个单例类,能够考虑这样作:服务器
mysingleton.py多线程
class Singleton(object): def foo(self): pass singleton = Singleton()
将上面的代码保存在文件 mysingleton.py
中,要使用时,直接在其余文件中导入此文件中的对象,这个对象便是单例模式的对象并发
from a import singleton
2.使用装饰器
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): a = 1 def __init__(self, x=0): self.x = x a1 = A(2) a2 = A(3)
3.使用类
class Singleton(object): def __init__(self): pass @classmethod def instance(cls, *args, **kwargs): if not hasattr(Singleton, "_instance"): Singleton._instance = Singleton(*args, **kwargs) return Singleton._instance
通常状况,你们觉得这样就完成了单例模式,可是这样当使用多线程时会存在问题ide
class Singleton(object): def __init__(self): pass @classmethod def instance(cls, *args, **kwargs): if not hasattr(Singleton, "_instance"): Singleton._instance = Singleton(*args, **kwargs) return Singleton._instance import threading def task(arg): obj = Singleton.instance() print(obj) for i in range(10): t = threading.Thread(target=task,args=[i,]) t.start()
程序执行后,打印结果以下:函数
<__main__.Singleton object at 0x02C933D0> <__main__.Singleton object at 0x02C933D0> <__main__.Singleton object at 0x02C933D0> <__main__.Singleton object at 0x02C933D0> <__main__.Singleton object at 0x02C933D0> <__main__.Singleton object at 0x02C933D0> <__main__.Singleton object at 0x02C933D0> <__main__.Singleton object at 0x02C933D0> <__main__.Singleton object at 0x02C933D0> <__main__.Singleton object at 0x02C933D0>
看起来也没有问题,那是由于执行速度过快,若是在init方法中有一些IO操做,就会发现问题了,下面咱们经过time.sleep模拟post
咱们在上面__init__方法中加入如下代码:
def __init__(self): import time time.sleep(1)
从新执行程序后,结果以下
<__main__.Singleton object at 0x034A3410> <__main__.Singleton object at 0x034BB990> <__main__.Singleton object at 0x034BB910> <__main__.Singleton object at 0x034ADED0> <__main__.Singleton object at 0x034E6BD0> <__main__.Singleton object at 0x034E6C10> <__main__.Singleton object at 0x034E6B90> <__main__.Singleton object at 0x034BBA30> <__main__.Singleton object at 0x034F6B90> <__main__.Singleton object at 0x034E6A90>
问题出现了!按照以上方式建立的单例,没法支持多线程
解决办法:加锁!未加锁部分并发执行,加锁部分串行执行,速度下降,可是保证了数据安全
import time import threading class Singleton(object): _instance_lock = threading.Lock() def __init__(self): time.sleep(1) @classmethod def instance(cls, *args, **kwargs): with Singleton._instance_lock: if not hasattr(Singleton, "_instance"): Singleton._instance = Singleton(*args, **kwargs) return Singleton._instance def task(arg): obj = Singleton.instance() print(obj) for i in range(10): t = threading.Thread(target=task,args=[i,]) t.start() time.sleep(20) obj = Singleton.instance() print(obj)
打印结果以下:
<__main__.Singleton object at 0x02D6B110> <__main__.Singleton object at 0x02D6B110> <__main__.Singleton object at 0x02D6B110> <__main__.Singleton object at 0x02D6B110> <__main__.Singleton object at 0x02D6B110> <__main__.Singleton object at 0x02D6B110> <__main__.Singleton object at 0x02D6B110> <__main__.Singleton object at 0x02D6B110> <__main__.Singleton object at 0x02D6B110> <__main__.Singleton object at 0x02D6B110>
这样就差很少了,可是仍是有一点小问题,就是当程序执行时,执行了time.sleep(20)后,下面实例化对象时,此时已是单例模式了,但咱们仍是加了锁,这样不太好,再进行一些优化,把intance方法,改为下面的这样就行:
@classmethod def instance(cls, *args, **kwargs): if not hasattr(Singleton, "_instance"): with Singleton._instance_lock: if not hasattr(Singleton, "_instance"): Singleton._instance = Singleton(*args, **kwargs) return Singleton._instance
这样,一个能够支持多线程的单例模式就完成了

import time import threading class Singleton(object): _instance_lock = threading.Lock() def __init__(self): time.sleep(1) @classmethod def instance(cls, *args, **kwargs): if not hasattr(Singleton, "_instance"): with Singleton._instance_lock: if not hasattr(Singleton, "_instance"): Singleton._instance = Singleton(*args, **kwargs) return Singleton._instance def task(arg): obj = Singleton.instance() print(obj) for i in range(10): t = threading.Thread(target=task,args=[i,]) t.start() time.sleep(20) obj = Singleton.instance() print(obj)
这种方式实现的单例模式,使用时会有限制,之后实例化必须经过 obj = Singleton.instance()
若是用 obj=Singleton() ,这种方式获得的不是单例
4.基于__new__方法实现(推荐使用,方便)
经过上面例子,咱们能够知道,当咱们实现单例时,为了保证线程安全须要在内部加入锁
咱们知道,当咱们实例化一个对象时,是先执行了类的__new__方法(咱们没写时,默认调用object.__new__),实例化对象;而后再执行类的__init__方法,对这个对象进行初始化,全部咱们能够基于这个,实现单例模式
import threading class Singleton(object): _instance_lock = threading.Lock() def __init__(self): pass def __new__(cls, *args, **kwargs): if not hasattr(Singleton, "_instance"): with Singleton._instance_lock: if not hasattr(Singleton, "_instance"): Singleton._instance = object.__new__(cls) return Singleton._instance obj1 = Singleton() obj2 = Singleton() print(obj1,obj2) def task(arg): obj = Singleton() print(obj) for i in range(10): t = threading.Thread(target=task,args=[i,]) t.start()
打印结果以下:
<__main__.Singleton object at 0x038B33D0> <__main__.Singleton object at 0x038B33D0> <__main__.Singleton object at 0x038B33D0> <__main__.Singleton object at 0x038B33D0> <__main__.Singleton object at 0x038B33D0> <__main__.Singleton object at 0x038B33D0> <__main__.Singleton object at 0x038B33D0> <__main__.Singleton object at 0x038B33D0> <__main__.Singleton object at 0x038B33D0> <__main__.Singleton object at 0x038B33D0> <__main__.Singleton object at 0x038B33D0> <__main__.Singleton object at 0x038B33D0>
采用这种方式的单例模式,之后实例化对象时,和平时实例化对象的方法同样 obj = Singleton()
5.基于metaclass方式实现
相关知识
""" 1.类由type建立,建立类时,type的__init__方法自动执行,类() 执行type的 __call__方法(类的__new__方法,类的__init__方法) 2.对象由类建立,建立对象时,类的__init__方法自动执行,对象()执行类的 __call__ 方法 """
例子:
class Foo: def __init__(self): pass def __call__(self, *args, **kwargs): pass obj = Foo() # 执行type的 __call__ 方法,调用 Foo类(是type的对象)的 __new__方法,用于建立对象,而后调用 Foo类(是type的对象)的 __init__方法,用于对对象初始化。 obj() # 执行Foo的 __call__ 方法
元类的使用
class SingletonType(type): def __init__(self,*args,**kwargs): super(SingletonType,self).__init__(*args,**kwargs) def __call__(cls, *args, **kwargs): # 这里的cls,即Foo类 print('cls',cls) obj = cls.__new__(cls,*args, **kwargs) cls.__init__(obj,*args, **kwargs) # Foo.__init__(obj) return obj class Foo(metaclass=SingletonType): # 指定建立Foo的type为SingletonType def __init__(self,name): self.name = name def __new__(cls, *args, **kwargs): return object.__new__(cls) obj = Foo('xx')
实现单例模式
import threading class SingletonType(type): _instance_lock = threading.Lock() def __call__(cls, *args, **kwargs): if not hasattr(cls, "_instance"): with SingletonType._instance_lock: if not hasattr(cls, "_instance"): cls._instance = super(SingletonType,cls).__call__(*args, **kwargs) return cls._instance class Foo(metaclass=SingletonType): def __init__(self,name): self.name = name obj1 = Foo('name') obj2 = Foo('name') print(obj1,obj2)