python单例模式
python单例模式记录
1、单例模式的应用场景
资源共享:当多个对象需要共享同一个资源时,可以使用单例模式来管理该资源的访问。例如,数据库连接池、日志记录器等。
配置信息:当需要在应用程序中共享配置信息时,可以使用单例模式来保存和访问配置对象。这样可以确保配置信息的一致性和全局可访问性。
缓存管理:在需要缓存数据的场景中,可以使用单例模式来管理缓存对象。这样可以避免重复创建缓存对象,提高性能和资源利用率。
对话框或窗口管理:在图形用户界面(GUI)应用程序中,可以使用单例模式来管理对话框或窗口对象。这样可以确保只有一个实例对象存在,并且可以方便地进行访问和控制。
日志记录:在需要记录应用程序日志的场景中,可以使用单例模式来管理日志记录器对象。这样可以确保只有一个日志记录器实例,并且可以在整个应用程序中方便地使用。
2、当一个类定义被执行时,将发生以下步骤:
解析 MRO 条目 确定适当的元类 准备类命名空间 执行类主体 创建类对象 参考:https://docs.python.org/zh-cn/3.7/reference/datamodel.html#customizing-class-creation
3、new()
调用以创建一个 cls 类的新实例。
new() 是一个静态方法 (因为是特例所以你不需要显式地声明),它会将所请求实例所属的类作为第一个参数。其余的参数会被传递给对象构造器表达式 (对类的调用)。new() 的返回值应为新对象实例 (通常是 cls 的实例)。
如果 new() 返回一个 cls 的实例,则新实例的 init() 方法会在之后被执行,例如 init(self[, ...]),其中 self 为新实例,其余的参数与被传递给 new() 的相同。
如果 new() 未返回一个 cls 的实例,则新实例的 init() 方法就不会被执行。
4、init()
在实例 (通过 new()) 被创建之后,返回调用者之前调用。其参数与传递给类构造器表达式的参数相同。一个基类如果有 init() 方法,则其所派生的类如果也有 init() 方法,就必须显式地调用它以确保实例基类部分的正确初始化;例如: super().init([args...]).
因为对象是由 new() 和 init() 协作构造完成的 (由 new() 创建,并由 init() 定制),所以 init() 返回的值只能是 None,否则会在运行时引发 TypeError。
5、非线程安全的单例模式
非线程安全
import time
class Singleton:
_instance = None
def __new__(cls, *args, **kwargs):
if not cls._instance:
time.sleep(1)
cls._instance = super().__new__(cls, *args, **kwargs)
return cls._instance
#instance1 = Singleton()
#instance2 = Singleton()
#print(instance1 is instance2) # 输出: True
import threading
def create_singleton():
instance = Singleton()
print(instance)
threads = []
for _ in range(10):
t = threading.Thread(target=create_singleton)
threads.append(t)
t.start()
for t in threads:
t.join()
<__main__.Singleton object at 0x7f8269c91f60>
<__main__.Singleton object at 0x7f8269c91000>
<__main__.Singleton object at 0x7f8269c90df0>
<__main__.Singleton object at 0x7f8269c90be0>
<__main__.Singleton object at 0x7f8269c909d0>
<__main__.Singleton object at 0x7f8269c907c0>
<__main__.Singleton object at 0x7f8269c905b0>
<__main__.Singleton object at 0x7f8269c903a0>
<__main__.Singleton object at 0x7f8269c90190>
<__main__.Singleton object at 0x7f8269c91d20>
6、线程安全的单例模式
线程安全的
import threading
class Singleton:
_instance = None
_lock = threading.Lock()
def __new__(cls, *args, **kwargs):
thread_id = threading.current_thread()
if not cls._instance:
print("我再等待着", thread_id)
with cls._lock:
print("我进来了",thread_id)
if not cls._instance:
cls._instance = super().__new__(cls, *args, **kwargs)
print("我直接返回了", thread_id)
return cls._instance
def create_singleton():
instance = Singleton()
print(instance)
threads = []
for _ in range(10):
t = threading.Thread(target=create_singleton)
threads.append(t)
t.start()
for t in threads:
t.join()
我再等待着 <Thread(Thread-1 (create_singleton), started 139852282197760)>
我进来了 <Thread(Thread-1 (create_singleton), started 139852282197760)>
我直接返回了 <Thread(Thread-1 (create_singleton), started 139852282197760)>
<__main__.Singleton object at 0x7f31e59b90c0>
我直接返回了 <Thread(Thread-2 (create_singleton), started 139852282197760)>
<__main__.Singleton object at 0x7f31e59b90c0>
我直接返回了 <Thread(Thread-3 (create_singleton), started 139852282197760)>
<__main__.Singleton object at 0x7f31e59b90c0>
我直接返回了 <Thread(Thread-4 (create_singleton), started 139852282197760)>
<__main__.Singleton object at 0x7f31e59b90c0>
我直接返回了 <Thread(Thread-5 (create_singleton), started 139852282197760)>
<__main__.Singleton object at 0x7f31e59b90c0>
我直接返回了 <Thread(Thread-6 (create_singleton), started 139852282197760)>
<__main__.Singleton object at 0x7f31e59b90c0>
我直接返回了 <Thread(Thread-7 (create_singleton), started 139852282197760)>
<__main__.Singleton object at 0x7f31e59b90c0>
我直接返回了 <Thread(Thread-8 (create_singleton), started 139852282197760)>
<__main__.Singleton object at 0x7f31e59b90c0>
我直接返回了 <Thread(Thread-9 (create_singleton), started 139852282197760)>
<__main__.Singleton object at 0x7f31e59b90c0>
我直接返回了 <Thread(Thread-10 (create_singleton), started 139852282197760)>
<__main__.Singleton object at 0x7f31e59b90c0>
7、参考
https://docs.python.org/zh-cn/3.7/library/threading.html#using-locks-conditions-and-semaphores-in-the-with-statement
https://docs.python.org/zh-cn/3.7/library/threading.html#lock-objects