github地址:https://github.com/cheesezh/python_design_patternshtml
单例模式(Singleton Pattern)是一种经常使用的软件设计模式,该模式的主要目的是确保某一个类只有一个实例存在
。当你但愿在整个系统中,某个类只能出现一个实例时,单例模式就能派上用场。python
好比,某个服务器程序的配置信息存放在一个文件中,客户端经过一个 AppConfig 的类来读取配置文件的信息。若是在程序运行期间,有不少地方都须要使用配置文件的内容,也就是说,不少地方都须要建立 AppConfig 对象的实例,这就致使系统中存在多个 AppConfig 的实例对象,而这样会严重浪费内存资源,尤为是在配置文件内容不少的状况下。事实上,相似 AppConfig 这样的类,咱们但愿在程序运行期间只存在一个实例对象。git
在 Python 中,咱们能够用多种方法来实现单例模式。github
其实,Python 的模块就是自然的单例模式,由于模块在第一次导入时,会生成 .pyc 文件,当第二次导入时,就会直接加载 .pyc 文件,而不会再次执行模块代码。所以,咱们只需把相关的函数和数据定义在一个模块中,就能够得到一个单例对象了。若是咱们真的想要一个单例类,能够考虑这样作:设计模式
# mysingleton.py class Singleton(object): def foo(self): pass singleton = Singleton()
将上面的代码保存在文件 mysingleton.py 中,要使用时,直接在其余文件中导入此文件中的对象,这个对象便是单例模式的对象安全
from a import singleton
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) print(a1) print(a2)
<__main__.A object at 0x103496668> <__main__.A object at 0x103496668>
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
通常状况,你们觉得这样就完成了单例模式,可是这样当使用多线程时会存在问题
。服务器
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 0x1033e84a8> <__main__.Singleton object at 0x1033e84a8> <__main__.Singleton object at 0x1033e84a8> <__main__.Singleton object at 0x1033e84a8> <__main__.Singleton object at 0x1033e84a8> <__main__.Singleton object at 0x1033e84a8> <__main__.Singleton object at 0x1033e84a8> <__main__.Singleton object at 0x1033e84a8> <__main__.Singleton object at 0x1033e84a8> <__main__.Singleton object at 0x1033e84a8>
看起来也没有问题,那是由于执行速度过快,若是在init方法中有一些IO操做,就会发现问题了,下面咱们经过time.sleep模拟多线程
class Singleton(object): def __init__(self): import time time.sleep(0.5) 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 0x1033b79e8> <__main__.Singleton object at 0x1033b7e10> <__main__.Singleton object at 0x103401ef0> <__main__.Singleton object at 0x103401c18> <__main__.Singleton object at 0x103401048> <__main__.Singleton object at 0x103401dd8> <__main__.Singleton object at 0x103401b00> <__main__.Singleton object at 0x103401eb8> <__main__.Singleton object at 0x103401a58> <__main__.Singleton object at 0x103401fd0>
问题出现了!按照以上方式建立的单例,没法支持多线程。并发
解决办法:加锁!未加锁部分并发执行,加锁部分串行执行,速度下降,可是保证了数据安全函数
import time import threading class Singleton(object): _instance_lock = threading.Lock() def __init__(self): time.sleep(0.5) @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(5) obj = Singleton.instance() print(obj)
<__main__.Singleton object at 0x103401b00> <__main__.Singleton object at 0x103401b00> <__main__.Singleton object at 0x103401b00> <__main__.Singleton object at 0x103401b00> <__main__.Singleton object at 0x103401b00> <__main__.Singleton object at 0x103401b00> <__main__.Singleton object at 0x103401b00> <__main__.Singleton object at 0x103401b00> <__main__.Singleton object at 0x103401b00> <__main__.Singleton object at 0x103401b00> <__main__.Singleton object at 0x103401b00>
这样就差很少了,可是仍是有一点小问题,就是当程序执行时,执行了time.sleep(5)后,下面实例化对象时,此时已是单例模式了,但咱们仍是加了锁,这样不太好,再进行一些优化,须要修改一下intance方法。
import time import threading class Singleton(object): _instance_lock = threading.Lock() def __init__(self): time.sleep(0.5) @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(5) obj = Singleton.instance() print(obj)
<__main__.Singleton object at 0x1033db550> <__main__.Singleton object at 0x1033db550> <__main__.Singleton object at 0x1033db550> <__main__.Singleton object at 0x1033db550> <__main__.Singleton object at 0x1033db550> <__main__.Singleton object at 0x1033db550> <__main__.Singleton object at 0x1033db550> <__main__.Singleton object at 0x1033db550> <__main__.Singleton object at 0x1033db550> <__main__.Singleton object at 0x1033db550> <__main__.Singleton object at 0x1033db550>
这种方式实现的单例模式,使用时会有限制,之后实例化必须经过obj = Singleton.instance()
,若是用obj=Singleton()
,这种方式获得的不是单例。
经过上面例子,咱们能够知道,当咱们实现单例时,为了保证线程安全须要在内部加入锁。
咱们知道,当咱们实例化一个对象时,是先执行了类的__new__方法(咱们没写时,默认调用object.__new__)实例化对象;而后再执行类的__init__方法,对这个对象进行初始化,全部咱们能够基于这个机制,实现单例模式。
import threading import time class Singleton(object): _instance_lock = threading.Lock() def __init__(self): time.sleep(0.5) 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 0x103483b70> <__main__.Singleton object at 0x103483b70> <__main__.Singleton object at 0x103483b70> <__main__.Singleton object at 0x103483b70> <__main__.Singleton object at 0x103483b70> <__main__.Singleton object at 0x103483b70> <__main__.Singleton object at 0x103483b70> <__main__.Singleton object at 0x103483b70> <__main__.Singleton object at 0x103483b70> <__main__.Singleton object at 0x103483b70> <__main__.Singleton object at 0x103483b70> <__main__.Singleton object at 0x103483b70>
采用这种方式的单例模式,之后实例化对象时,和平时实例化对象的方法同样obj = Singleton()
class Foo: def __init__(self): print("Foo __init__") def __call__(self, *args, **kwargs): print("Foo __call__") # 执行type的 __call__ 方法 # 调用 Foo类(是type的对象)的 __new__方法,用于建立对象 # 而后调用 Foo类(是type的对象)的 __init__方法,用于对对象初始化。 obj = Foo() # 执行Foo的 __call__ 方法 obj()
Foo __init__ 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')
cls <class '__main__.Foo'>
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) print(obj2)
<__main__.Foo object at 0x10348d908> <__main__.Foo object at 0x10348d908>
参考文章: Python中的单例模式的几种实现方式的及优化