浅谈Python设计模式 -- 单例模式

单例模式:

就是确保一个类只有一个实例.当你希望整个系统中,某个类只有一个实例时,单例模式就派上了用场。单例模式能够保证调用者读到一致的信息。

另外,我将单例模式又分为了两种类型:

初始化动作只执行一次:适用于初始化参数固定的场景。如初始化项目配置文件。

每次都初始化:适用于初始化参数随调用者的不同而变化的场景,注意每次初始化都会影响所有调用者读取到的信息。

实例:

某个服务器的配置信息存在在一个文件中,客户端通过AppConfig类来读取配置文件的信息.如果程序的运行的过程中,很多地方都会用到配置文件信息,则就需要创建很多的AppConfig实例,这样就导致内存中有很多AppConfig对象的实例,造成资源的浪费.其实这个时候AppConfig我们希望它只有一份,就可以使用单例模式.
 

代码实现:

只介绍一种基于__new__方法实现的单例模式(推荐使用,方便)。

此方式每次调用对象,__init__方法都会重新执行,虽然都是一个实例对象。

而采用元类方式实现的单例模式。__init__只有第一次调用对象时执行。

import threading, time
 
 
class Singleton(object):
    def __init__(self, *args, **kwargs):
        time.sleep(1)
        pass
    def __new__(cls, *args, **kwargs):
        if not hasattr(cls, '_instance'):
            cls._instance = super().__new__(cls)
        return cls._instance
 
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 0x034A3410>
<__main__.Singleton object at 0x034BB990>
<__main__.Singleton object at 0x034BB910>
<__main__.Singleton object at 0x034ADED0>
<__main__.Singleton object at 0x034E6BD0>
<__main__.Singleton object at 0x034E6C10>
<__main__.Singleton object at 0x034E6B90>
<__main__.Singleton object at 0x034BBA30>
<__main__.Singleton object at 0x034F6B90>
<__main__.Singleton object at 0x034E6A90>

问题出现了!按照以上方式创建的单例,无法支持多线程,因为最先执行的线程卡在init中,还没有实例化出_instance。所以其他线程依然可以正常实例化对象。

如何解决呢? 加锁:

import threading, time
 
 
class Singleton(object):
    _instance_lock = threading.Lock()
 
    def __init__(self, *args, **kwargs):
        time.sleep(1)
        pass
 
    def __new__(cls, *args, **kwargs):
        if not hasattr(cls, '_instance'):
            with cls._instance_lock:
                if not hasattr(cls, '_instance'):
                    cls._instance = super().__new__(cls)
 
            return cls._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()

博主实际开发中的应用:利用第三方SDK发短信功能、简历敏感信息屏蔽功能,offer生成功能。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值