• 欢迎访问搞代码网站,推荐使用最新版火狐浏览器和Chrome浏览器访问本网站!
  • 如果您觉得本站非常有看点,那么赶紧使用Ctrl+D 收藏搞代码吧

Python设计模式中单例模式的实现及在Tornado中的应用

python 搞代码 4年前 (2022-01-09) 20次浏览 已收录 0个评论

单例模式的实现方式
将类实例绑定到类变量上

class Singleton(object):  _instance = None  def __new__(cls, *args):    if not isinstance(cls._instance, cls):      cls._instance = super(Singleton, cls).__new__(cls, *args)    return cls._instance

但是子类在继承后可以重写__new__以失去单例特性

class D(Singleton):  def __new__(cls, *args):    return super(D, cls).__new__(cls, *args)

使用装饰器实现

def singleton(_cls):  inst = {}  def getinstance(*args, **kwargs):    if _cls not in inst:      inst[_cls] = _cls(*args, **kwargs)    return inst[_cls]  return getinstance@singletonclass MyClass(object):  pass

问题是这样装饰以后返回的不是类而是函数,当然你可以singleton里定义一个类来解决问题,但这样就显得很麻烦了

使用__metaclass__,这个方式最推荐

class Singleton(type):  _inst = {}    def __call__(cls, *args, **kwargs):    if cls not in cls._inst:      cls._inst[cls] = super(Singleton, cls).__call__(*args)    return cls._inst[cls]class MyClass(object):  __metaclass__ = Singleton

Tornado中的单例模式运用
来看看tornado.IOLoop中的单例模式:

class IOLoop(object):  @staticmethod  def instance():    """Returns a global `IOLoop` instance.Most applications have a single, global `IOLoop` running on themain thread. Use this method to get this instance fromanother thread. To get the current thread's `IOLoop`, use `current()`."""    if not hasattr(IOLoop, "_instance"):      with IOLoop._instance_lock:        if not hasattr(IOLoop, "_instance"):          # New instance after double check          IOLoop._instance = IOLoop()    return IOLoop._instance

为什么这里要double check?来看个这里面简单的单例模式,先来看看代码:

class Singleton(object):  @staticmathod  def instance():    if not hasattr(Singleton, '_instance'):      Singleton._instance = Singleton()    return Singleton._instance

在 Python 里,可以在真正的构造函数__new__里做文章:

class Singleton(obje<div style="color:transparent">本文来源gaodai.ma#com搞##代!^码网(</div>ct):  def __new__(cls, *args, **kwargs):    if not hasattr(cls, '_instance'):      cls._instance = super(Singleton, cls).__new__(cls, *args, **kwargs)    return cls._instance

这种情况看似还不错,但是不能保证在多线程的环境下仍然好用,看图:

出现了多线程之后,这明显就是行不通的。

1.上锁使线程同步
上锁后的代码:

import threadingclass Singleton(object):  _instance_lock = threading.Lock()    @staticmethod  def instance():    with Singleton._instance_lock:      if not hasattr(Singleton, '_instance'):        Singleton._instance = Singleton()    return Singleton._instance

这里确实是解决了多线程的情况,但是我们只有实例化的时候需要上锁,其它时候Singleton._instance已经存在了,不需要锁了,但是这时候其它要获得Singleton实例的线程还是必须等待,锁的存在明显降低了效率,有性能损耗。

2.全局变量
在 Java/C++ 这些语言里还可以利用全局变量的方式解决上面那种加锁(同步)带来的问题:

class Singleton {  private static Singleton instance = new Singleton();    private Singleton() {}    public static Singleton getInstance() {    return instance;  }  }

在 Python 里就是这样了:

class Singleton(object):  @staticmethod  def instance():    return _g_singleton_g_singleton = Singleton()# def get_instance():# return _g_singleton

但是如果这个类所占的资源较多的话,还没有用这个实例就已经存在了,是非常不划算的,Python 代码也略显丑陋……

所以出现了像tornado.IOLoop.instance()那样的double check的单例模式了。在多线程的情况下,既没有同步(加锁)带来的性能下降,也没有全局变量直接实例化带来的资源浪费。

3.装饰器

如果使用装饰器,那么将会是这样:

import functoolsdef singleton(cls):  ''' Use class as singleton. '''  cls.__new_original__ = cls.__new__  @functools.wraps(cls.__new__)  def singleton_new(cls, *args, **kw):    it = cls.__dict__.get('__it__')    if it is not None:      return it    cls.__it__ = it = cls.__new_original__(cls, *args, **kw)    it.__init_original__(*args, **kw)    return it  cls.__new__ = singleton_new  cls.__init_original__ = cls.__init__  cls.__init__ = object.__init__  return cls## Sample use:#@singletonclass Foo:  def __new__(cls):    cls.x = 10    return object.__new__(cls)  def __init__(self):    assert self.x == 10    self.x = 15assert Foo().x == 15Foo().x = 20assert Foo().x == 20

def singleton(cls):  instance = cls()  instance.__call__ = lambda: instance  return instance## Sample use#@singletonclass Highlander:  x = 100  # Of course you can have any attributes or methods you like.Highlander() is Highlander() is Highlander #=> Trueid(Highlander()) == id(Highlander) #=> TrueHighlander().x == Highlander.x == 100 #=> TrueHighlander.x = 50Highlander().x == Highlander.x == 50 #=> True

搞代码网(gaodaima.com)提供的所有资源部分来自互联网,如果有侵犯您的版权或其他权益,请说明详细缘由并提供版权或权益证明然后发送到邮箱[email protected],我们会在看到邮件的第一时间内为您处理,或直接联系QQ:872152909。本网站采用BY-NC-SA协议进行授权
转载请注明原文链接:Python设计模式中单例模式的实现及在Tornado中的应用

喜欢 (0)
[搞代码]
分享 (0)
发表我的评论
取消评论

表情 贴图 加粗 删除线 居中 斜体 签到

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址