单例模式
核心作用
保证一个类只有一个实例,并且提供一个访问该实例的全局访问点
常见的应用场景
- windows的Task Manager (任务管理器)就是很典型的单例模式
- windows的回收站也是典型的单例应用,在整个系统运行过程中,回收站一直维持着仅有的一个实例
- 项目中,读取配置文件的类,一般也只有一个对象,没有必要每次使用配置文件数据的时候都new一个对象去读取
- 网站计数器,一般也是采用单例模式实现,否则难以同步
- 应用程序的日志应用,一般采用单例模式实现,这一般是由于共享的日志文件一直处于打开状态,因为只能有一个实例去操作,否则内存不好追加。
- 数据库连接池的设计一般也是采用的单例模式,因为数据库连接也是一种数据库资源
- Python 的模块就是天然的单例模式,因为模块在第一次导入时,会生成
.pyc
文件,当第二次导入时,就会直接加载.pyc
文件,而不会再次执行模块代码
单例模式的优点
由于单例模式只生成一个实例,减少了系统性能开销,当一个对象的产生需要比较多的资源时,如读取配置、产生其他依赖对象时,则可以通过在应用启动时直接产生一个单例对象,然后永久驻留内存的方式来解决
单例模式可以再系统设置全局的访问点,优化共享资源访问,例如可以设计一个单例类,负责所有数据表的映射处理
常见的五种单例模式实现方式
- 主要:
- 饿汉模式——单例对象立即加载(线程安全、调用效率高,但是不能延时加载)
- 懒汉模式(线程安全,调用效率不高,但是可以延时加载)
- 其他:
- 双重检测锁式(Java不建议使用)
- 静态内部类式(线程安全,调用率高,同时也可以延时加载)
- 枚举单例(线程安全,调用效率高,不能延时加载)
如何选用
- 单例对象 占用 资源少,不要 延时加载:
- 枚举式 好于 饿汉式
- 单例对象 占用 资源大,需要 延时加载:
- 静态内部类式 好于 懒汉式
python中单例模式的实现方式
本来想整理一下,以上说的几种常见的单例实现模式在Python中的实现表现,但是感觉对Java和Python理解的深度不够,懵懵懂懂之间,不敢胡乱总结,只得贴一些python自己的实现方式,没法进行对比了。先继续学习,深入了解一些再回来整理。
使用模块
Python 的模块就是天然的单例模式,因为模块在第一次导入时,会生成 .pyc 文件,当第二次导入时,就会直接加载 .pyc 文件,而不会再次执行模块代码。 因此,我们只需把相关的函数和数据定义在一个模块中,就可以获得一个单例对象了。如果我们真的想要一个单例类,可以考虑这样做:
1 | # mysingleton.py |
使用 __new__
使用 __new__
来控制实例的创建过程,这里没有线程的问题,下面的例子就是演示多线程的时候,看看是不是出问题,结果没有。
1 | class Singleton(object): |
使用装饰器
装饰器(decorator)可以动态地修改一个类或函数的功能。
1 | def singleton(cls, *args, **kw): |
虽然进行了两次实例化,但仍为同一个实例
使用 元类(metaclass)
- 类由type创建,创建类时,type的__init__方法自动执行,类() 执行type的 __call__方法(类的__new__方法,类的__init__方法)
- 对象由类创建,创建对象时,类的__init__方法自动执行,对象()执行类的 call 方法
1 | import threading |