使用模块
其实,Python 的模块就是天然的单例模式,因为模块在第一次导入时,会生成 .pyc 文件,
当第二次导入时,就会直接加载 .pyc 文件,而不会再次执行模块代码。
因此,我们只需把相关的函数和数据定义在一个模块中,就可以获得一个单例对象了。
如果我们真的想要一个单例类,可以考虑这样做
1.创建test1.py文件,添加以下代码
class Sington:
def __init__(self,*args,**kwargs):
self.name = args[0]
self.age = kwargs["age"]
sington = Sington("nick",age=23)
2.创建test2.py文件,在test2.py文件里面导入test1.py文件里面的sington
from test1 import sington
print(sington.name)
使用装饰器实现单例模式
代码如下:代码的思想就是在装饰器里面放一个字典,这个字典会存放所有需要使用单例模式的类的映射.
当不存在映射时,就创建一个对象进去,存在就略过
from functools import wraps
def sington(cls):
_instances = {}
@wraps(cls)
def wrapper(*args,**kwargs):
if cls not in _instances:
_instances[cls] = cls(*args,**kwargs)
return _instances[cls]
return wrapper
@sington
class Test:
def __init__(self,*args,**kwargs):
pass
test1 = Test()
test2 = Test()
print(id(test1) == id(test2)) # True
使用类的方式 (保证线程安全)
有陷阱的创建方式: 线程不安全
# 由于实例化对象的时候先调用__new__方法,再调用__init__方法,如果__init__出现耗时操作,比如数据库连接
# 读取文本之类的,就会造成多线程并发的情况下(时间片轮转)多个线程同时调用了instance方法.
# 就会造成多个对象出来,虽然最后一个执行完的线程制造的对象会覆盖掉之前创建的对象,
# 但依然是不安全的
import threading
import time
class Singleton(object):
def __init__(self):
time.sleep(1)
@classmethod
def instance(cls, *args, **kwargs):
if not hasattr(Singleton, "_instance"):
Singleton._instance = Singleton(*args, **kwargs)
return Singleton._instance
def task():
obj = Singleton.instance()
print(id(obj))
for i in range(10):
t = threading.Thread(target=task)
t.start()
解决方法:枷锁
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():
obj = Singleton.instance()
print(id(obj))
list1 = list()
for i in range(10):
t = threading.Thread(target=task)
t.start()
list1.append(t)
for i in list1:
i.join()
obj = Singleton.instance()
print(obj)
方式三:基于new的线程安全
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():
obj = Singleton()
print(obj)
for i in range(10):
t = threading.Thread(target=task)
t.start()