什么是单例模式 ?
单例模式(Singleton Pattern)是软件设计中的一种常用设计模式,其目的是在一个进程中,确保某一个类(class)只有一个实例(instance)存在。
例如,当我们在操作数据库时,多个服务都要调用数据库的 connection ,其配置信息都是相同的,这种情况就可以使用单例模式。在该系统中,只使用一个用于连接数据库的 connection 实例
单例模式的实现方式
1. 模块构建
Python 的模块就是天然的单例模式,模块在第一次导入的时候,会生成 .pyc
文件,就会直接加载.pyc
文件,而不会再次执行模块
因此,我们只需要把相关的函数和数据定义在一个模块中,就可以获得一个单例对象了。
Singleton.py
1 2 3 4 5 6
| class Singleton(object): def __int__(self): pass
singleton = Singleton()
|
当我们需要使用这个 instance 的时候,直接使用即可:
1
| from Singleton import singleton
|
装饰器
使用 dict 类型,以 key-value 方式存储类的实例和运行的函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| def singleton(cls): _instance = {} def _singleton(*args, **kwargs): if cls not in _instance: _instance[cls] = cls(*args, **kwargs) return _instance[cls] return _singleton
@singleton class A(object): def __init__(self, x): self.x = x
a1 = A(1) a2 = A(2)
print(a1 is a2)
|
类方法实现
使用方法 hasattr
方法判断类中是否已实现了对应的实例方法,实现了就直接返回,未返回就添加单例属性
1 2 3 4 5 6 7 8 9 10 11 12
| class Singleton(object): def __init__(self): pass @staticmethod def instance(cls, *args, **kwargs): if not hasattr(Singleton, "_instance"): Singleton._instance = Singleton(*args, **kwargs) return Singleton._instance
obj = Singleton.instance()
|
多线程场景
但是在多线程
的使用中,由于每个线程有自己的数据资源,所以会存在问题
。
1 2 3 4 5 6 7 8
| def task(arg): obj = Singleton.instance() print(obj)
for i in range(10): t = threading.Thread(target=task,args=[i,]) t.start()
|
以上的实例显示出的详情可以看到 obj 的 id 并不一致,解决办法就是加 锁
(mutex)
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| import time import threading
class Singleton(object): lock = threading.Lock() def __init__(self): time.sleep(1) @staticmethod def instance(cls, *args, **kwargs): with Singleton.lock: if not hasattr(Singleton, "_instance"): Singleton._instance = Singleton(*args, **kwargs) return Singleton._instance
|
以上实现方式对整个实例的创建过程都进行了加锁,可以进行优化:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| import time import threading
class Singleton(object): lock = threading.Lock() def __init__(self): time.sleep(1) @staticmethod def instance(cls, *args, **kwargs): if not hasattr(Singleton, "_instance"): with Singleton.lock: Singleton._instance = Singleton(*args, **kwargs) return Singleton._instance
|
但是这样的实现方式,需要借助 instance 方法
__new__
方法实现
一个类在被实例化的过程中,先是执行默认的__new__
方法,然后再执行__init__
方法初始化对象
1 2 3 4 5 6 7 8 9 10 11 12
| import threading
class Singleton(object): _instance_lock = threading.Lock() def __int__(self): pass def __new__(cls, *args, **kwargs): if not hasattr(cls, "_instance"): with cls._instance_lock: cls._instance = super.__new__(cls) return cls._instance
|
- 类由
type
创建,创建类时,type 的 __init__
方法自动执行,类() 的方式执行type
的__call__
方法(类的 new__、__init 方法)
- 对象由类创建,创建对象时,类的
__init__
方法自动执行,对象()执行类的__call__
方法
其实,我们就是要保证在创建类的时候,保证这个类只有一个实例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| 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.__call__(*args, **kwargs) return cls._instance class Foo(metaclass=SingletonType): def __int__(self, name): self.name = name
|