Python设计模式中单例模式的实现及在Tornado中的应用
单例模式的实现方式 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,*args) 使用装饰器实现 def singleton(_cls): inst = {} def getinstance(*args,**kwargs): if _cls not in inst: inst[_cls] = _cls(*args,**kwargs) return inst[_cls] return getinstance @singleton class 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
class IOLoop(object): @staticmethod def instance(): """Returns a global `IOLoop` instance. Most applications have a single,global `IOLoop` running on the main thread. Use this method to get this instance from another 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(object): def __new__(cls,**kwargs): if not hasattr(cls,'_instance'): cls._instance = super(Singleton,**kwargs) return cls._instance 这种情况看似还不错,但是不能保证在多线程的环境下仍然好用,看图: 出现了多线程之后,这明显就是行不通的。 1.上锁使线程同步 import threading class 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.全局变量 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 functools def singleton(cls): ''' Use class as singleton. ''' cls.__new_original__ = cls.__new__ @functools.wraps(cls.__new__) def singleton_new(cls,**kw): it = cls.__dict__.get('__it__') if it is not None: return it cls.__it__ = it = cls.__new_original__(cls,**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: # @singleton class Foo: def __new__(cls): cls.x = 10 return object.__new__(cls) def __init__(self): assert self.x == 10 self.x = 15 assert Foo().x == 15 Foo().x = 20 assert Foo().x == 20 def singleton(cls): instance = cls() instance.__call__ = lambda: instance return instance # # Sample use # @singleton class Highlander: x = 100 # Of course you can have any attributes or methods you like. Highlander() is Highlander() is Highlander #=> True id(Highlander()) == id(Highlander) #=> True Highlander().x == Highlander.x == 100 #=> True Highlander.x = 50 Highlander().x == Highlander.x == 50 #=> True (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |