国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 編程 > Python > 正文

Python設計模式中單例模式的實現及在Tornado中的應用

2020-01-04 17:40:12
字體:
來源:轉載
供稿:網友
這篇文章主要介紹了Python設計模式中單例模式的實現及在Tornado中的應用,講解了單例模式用于設計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, 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(object):  def __new__(cls, *args, **kwargs):    if not hasattr(cls, '_instance'):      cls._instance = super(Singleton, cls).__new__(cls, *args, **kwargs)    return cls._instance

這種情況看似還不錯,但是不能保證在多線程的環境下仍然好用,看圖:

Python設計模式中單例模式的實現及在Tornado中的應用

出現了多線程之后,這明顯就是行不通的。

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

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 鄂托克前旗| 商丘市| 无锡市| 靖州| 蓬溪县| 景谷| 房产| 治县。| 德令哈市| 五家渠市| 巩义市| 博客| 甘肃省| 横山县| 东辽县| 柳州市| 南漳县| 固阳县| 城步| 镇坪县| 彩票| 水城县| 海宁市| 榆中县| 耿马| 界首市| 乌兰察布市| 福泉市| 桑植县| 大丰市| 嘉定区| 旺苍县| 岳池县| 武城县| 绥芬河市| 香格里拉县| 井研县| 卓资县| 施甸县| 镇雄县| 建阳市|