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, 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
@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
Tornado中的单例模式运用
来看看tornado.IOLoop中的单例模式:
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, *args, **kwargs):
if not hasattr(cls, '_instance'):
cls._instance = super(Singleton, cls).new(cls, *args, **kwargs)
return cls._instance
这种情况看似还不错,但是不能保证在多线程的环境下仍然好用,看图:
201632180733229.png (683×463)
出现了多线程之后,这明显就是行不通的。
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.全局变量
在 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 functools
def 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:
@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
Python设计模式中单例模式的实现及在Tornado中的应用的更多相关文章
- python设计模式之单例模式(一)
前言 单例模式是创建模式中比较常见和常用的模式,在程序执行的整个生命周期只存在一个实例对象. 系列文章 python设计模式之单例模式(一) python设计模式之常用创建模式总结(二) python ...
- python设计模式之单例模式(二)
上次我们简单了解了一下什么是单例模式,今天我们继续探究.上次的内容点这 python设计模式之单例模式(一) 上次们讨论的是GoF的单例设计模式,该模式是指:一个类有且只有一个对象.通常我们需要的是让 ...
- python设计模式之单例模式(转)
设计模式之单例模式 单例设计模式是怎么来的?在面向对象的程序设计中,当业务并发量非常大时,那么就会出现重复创建相同的对象,每创建一个对象就会开辟一块内存空间,而这些对象其实是一模一样的,那么有没有办法 ...
- python设计模式之单例模式(一)
单例设计模式的概念: 单例设计模式即确保类有且只有一个特定类型的对象,并提供全局访问点.一般我们操作数据库的时候为了避免统一资源产生互相冲突,创建单例模式可以维护数据的唯一性. 单例模式的特性: 确保 ...
- Python设计模式之单例模式
1.由于语言的特性不同,设计模式的实现方式和实现难度也会不同 2.有的模式已经在语言内置了,比如迭代器模式. 3.单例模式可以直接用模块级变量来实现 4.普通工厂模式可以直接通过传入"类名& ...
- 【python 设计模式】单例模式
单例模式(Singleton Pattern)是一种常用的软件设计模式,该模式的主要目的是确保某一个类只有一个实例存在.当你希望在整个系统中,某个类只能出现一个实例时,单例对象就能派上用场. 比如,某 ...
- python 设计模式之 单例模式
单例模式是做为"全局变量"的替代品出现的.所以它具有全局变量的特点:全局可见.贯穿应用程序的整个生命期,保证在程序执行中,某个类仅仅存在一个实例,所以通常不希望类中的构造函数被调用 ...
- python 设计模式之单例模式 Singleton Pattern
#引入 一个类被设计出来,就意味着它具有某种行为(方法),属性(成员变量).一般情况下,当我们想使用这个类时,会使用new 关键字,这时候jvm会帮我们构造一个该类的实例.这么做会比较耗费资源. 如果 ...
- python设计模式之--单例模式
python的单例模式就是一个类的实例只能自始自终自能创建一次.应用场景比如说数据库的连接池. #!/usr/bin/env python # coding=utf- class Foo(object ...
随机推荐
- bzoj4798[CEOI2015] Calvinball championship
这年头,n方跑1万的题已经不多了... 题意 bzoj4798 不知道怎么叙述这个题意... 分析 如果某个序列字典序小于给定的序列,我们不妨考虑从左到右第一个小于给定的序列的位置,并枚举这个位置的数 ...
- 【Jmeter】集合点Synchronizing Timer
集合点: 简单来理解一下,虽然我们的“性能测试”理解为“多用户并发测试”,但真正的并发是不存在的,为了更真实的实现并发这感念,我们可以在需要压力的地方设置集合点,每到输入用户名和密码登录时,所有的虚拟 ...
- [POJ1094] Sorting It All Out
link 题目大意 给出$m$个不等式关系,问可以从第几个开始确定所有之间的大小关系.若无解请输出是无法确定还是与已知矛盾. 试题分析 这题是真的是坑啊,尽然放在$floyd$传到闭包上面,还用二分, ...
- python基础----数据类型二
数据类型 计算机顾名思义就是可以做数学计算的机器,因此,计算机程序理所当然地可以处理各种数值.但是,计算机能处理的远不止数值,还可以处理文本.图形.音频.视频.网页等各种各样的数据,不同的数据,需要定 ...
- 网络编程----socket介绍、基于tcp协议的套接字实现、基于udp协议的套接字实现
一.客户端/服务器架构(C/S架构) 即C/S架构,包括: 1.硬件C/S架构(打印机) 2.软件C/S架 ...
- Codeforces Round #298 (Div. 2)A B C D
A. Exam time limit per test 1 second memory limit per test 256 megabytes input standard input output ...
- 洛谷P2345 奶牛集会
题目背景 MooFest, 2004 Open 题目描述 约翰的N 头奶牛每年都会参加“哞哞大会”.哞哞大会是奶牛界的盛事.集会上的活动很 多,比如堆干草,跨栅栏,摸牛仔的屁股等等.它们参加活动时会聚 ...
- [CQOI2009] 中位数 (前缀和)
[CQOI2009] 中位数 题目描述 给出1~n的一个排列,统计该排列有多少个长度为奇数的连续子序列的中位数是b.中位数是指把所有元素从小到大排列后,位于中间的数. 输入输出格式 输入格式: 第一行 ...
- angular2 获取到的数据无法实时更新的问题
在修改完组件数据之后调用下面两句: this.changeDetectorRef.markForCheck(); this.changeDetectorRef.detectChanges(); 注入到 ...
- python中如何优雅续行和换行
http://note.youdao.com/noteshare?id=8dbcb93991a89a6cfcd95580ed2198f0