16.python-单例模式
python-单例模式
单例模式适用于需要共享对象的场景
单例模式,也叫单子模式,是一种常用的软件设计模式。在应用这个模式时,单例对象的类必须保证只有一个实例存在。许多时候整个系统只需要拥有一个的全局对象,这样有利于我们协调系统整体的行为。比如在某个服务器程序中,该服务器的配置信息存放在一个文件中,这些配置数据由一个单例对象统一读取,然后服务进程中的其他对象再通过这个单例对象获取这些配置信息
- 单例模式是一种软件设计模式,而不是专属于某种编程语言的语法;
- 单例模式只有一个实例存在;
- 单例模式有助于协调系统的整体性、统一性;
- 每一次执行
类名()
返回的对象,内存地址是相同
优点:
1、在内存里只有一个实例,减少了内存的开销,尤其是频繁的创建和销毁实例
2、避免对资源的多重占用(比如写文件操作)
应用场景
- 资源共享的情况下,避免由于资源操作时导致的性能或损耗等。如日志文件,应用配置。
- 控制资源的情况下,方便资源之间的互相通信。如线程池等。
实现1-使用__new__
class Singleton:
__instance = None # 类属性,用于保存唯一的实例
def __new__(self):
if self.__instance is None:
self.__instance = object.__new__(self)
return self.__instance
s1 = Singleton()
s2 = Singleton()
print(s1)
print(s2)
# 执行结果
<__main__.Singleton object at 0x105149550>
<__main__.Singleton object at 0x105149550>
多线程加锁
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)
实现2-元类继承
元类是一种特殊的Python类,它可以用来创建其他类。使用元类可以将一个类转换为单例模式,后面我们会介绍元类
class Singleton(type):
_instances = {}
def __call__(cls, *args, **kwargs):
if cls not in cls._instances:
cls._instances[cls] = object.__call__(*args, **kwargs)
return cls._instances[cls]
class MyClass(metaclass=Singleton):
pass
class MyClass2(metaclass=Singleton):
pass
c1 = MyClass()
c2 = MyClass()
c3 = MyClass2()
c4 = MyClass2()
print(c1)
print(c2)
print(c3)
print(c4)
# 执行结果
<object object at 0x100cd9df0>
<object object at 0x100cd9df0>
<object object at 0x100cd9e40>
<object object at 0x100cd9e40>
多线程模式下的单例模式
# -*- coding: utf-8 -*-
import threading
def Singleton(cls):
# print("log singleton")
cls._instance = None
cls._lock = threading.Lock()
def __new__(*args, **kwargs):
# print(f"log new", args, kwargs) # 实际上args中也包含cls和相关的参数
with cls._lock:
if not cls._instance:
cls._instance = object.__new__(cls)
return cls._instance
cls.__new__ = __new__
return cls
@Singleton
class T:
def __init__(self, a):
self.a = a
def task(a):
s = T(a)
print(s)
def helper():
for i in range(5):
t = threading.Thread(target=task, args=(2,))
t.start()
if __name__ == '__main__':
helper()
实现3-函数装饰器实现
def singleton(cls):
instances = {}
def wrapper(*args, **kwargs):
if cls not in instances:
instances[cls] = cls(*args, **kwargs)
return instances[cls]
return wrapper
@singleton
class MyClass:
pass
@singleton
class MyClass2:
pass
c1 = MyClass()
c2 = MyClass()
c3 = MyClass2()
c4 = MyClass2()
print(c1)
print(c2)
print(c3)
print(c4)
# 执行结果
<__main__.MyClass object at 0x103419fa0>
<__main__.MyClass object at 0x103419fa0>
<__main__.MyClass2 object at 0x103419cd0>
<__main__.MyClass2 object at 0x103419cd0>
实现4-类方法
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 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)
实现5-直接导入
class Singleton(object):
def foo(self):
pass
singleton = Singleton()
将上面的代码保存在文件其他文件中,要使用时,直接在其他文件中导入此文件中的对象,这个对象即是单例模式的对象
from mysingleton import singleton
Note
单例在单线程模型下,是线程安全的,不管怎么样创建实例,都有且只有一个,而面对多线程任务时,一般的单例代码无法承担多线程任务,当有io延时操作时,会生成id不同的实例,所以如果需要实现多线程单例,那么就在创建实例时增加线程锁