python单例模式----实现数据库连接池

2021-06-08  本文已影响0人  修行的修行

单例模式介绍

适用场景:
单例模式只允许创建一个对象,因此节省内存,加快对象访问速度,因此对象需要被公用的场合适合使用,如多个模块使用同一个数据源连接对象等等。如:
1.需要频繁实例化然后销毁的对象。
2.创建对象时耗时过多或者耗资源过多,但又经常用到的对象。
3.有状态的工具类对象。
4.频繁访问数据库或文件的对象。
以下都是单例模式的经典使用场景:
1.资源共享的情况下,避免由于资源操作时导致的性能或损耗等。如上述中的日志文件,应用配置。还有windows系统的回收站和任务管理器,只能打开一个。
2.控制资源的情况下,方便资源之间的互相通信。多线程的线程池的设计一般就是采用单例模式,这是由于线程池要方便对池中的线程进行控制。

实现单例模式的几种方法

1. 使用模块

其实,python的模块就是天然的单例模式,因为模块在第一次导入的时候,会生成.pyc文件,当第二次导入的时候,就会直接加载.pyc文件,而不是再次执行模块代码.如果我们把相关的函数和数据定义在一个模块中,就可以获得一个单例对象了,再在另一个文件导入这个类实例.

# mysingleton.py
class Singleton(object): 
    def foo(self): 
        pass 
singleton = Singleton()

# work.py
from mysingleton import singleton
2. 使用装饰器

装饰器里面的外层变量定义一个字典,里面存放这个类的实例.当第一次创建的时候,就将这个实例保存到这个字典中.然后以后每次创建对象的时候,都去这个字典中判断一下,如果已经被实例化,就直接取这个实例对象.如果不存在就保存到字典中.

def singleton(cls):
    # 创建一个字典用来保存类的实例对象
    _instance = {}
    def _singleton(*args, **kwargs):
        # 先判断这个类有没有对象
        if cls not in _instance:
            _instance[cls] = cls(*args, **kwargs)  # 创建一个对象,并保存到字典当中
        # 将实例对象返回
        return _instance[cls]
    return _singleton


@singleton
class A(object):
    def __init__(self, x=0):
        self.x = x
        print('这是A的类的初始化方法')

a1 = A(2)
a2 = A(3)
print(id(a1) == id(a2))
3. 基于new方法

一个对象的实例化过程是先执行类的new方法,如果我们没有写,默认会调用object的new方法,返回一个实例化对象,然后再调用init方法,对这个对象进行初始化,我们可以根据这个实现单例

class Singleton(object):
    def __init__(self, *args, **kwargs):
        pass
    
    #在类的__new__方法中先判断是不是存在实例,如果存在实例,就直接返回,如果不存在实例就创建
    def __new__(cls, *args, **kwargs):
        if not hasattr(cls, '_instance'):
            Singleton._instance = super().__new__(cls)
        return Singleton._instance

a1 = Singleton()
a2 = Singleton()
print(id(a1) == id(a2))

数据库连接池

数据库连接池的设计一般是采用单例模式,因为数据库连接是一种数据库资源。数据库软件系统中使用数据库连接池,主要是节省打开或者关闭数据库连接所引起的效率损耗,这种效率上的损耗还是非常昂贵的。使用单例模式来维护连接池,就可以大大降低这种损耗,当需要频繁创建和销毁的对象时单例模式无疑可以提高系统的性能。

def connection_pool(n):
    assert n < 20  # 限制连接池实例数量
    def singleton(cls):
        # 创建一个列表用来保存类的实例对象
        _instance_list = list()
        def _singleton(*args, **kwargs):
            # 先判断这个实例列表有没有实例,即是不是类第一次init
            while len(_instance_list) < n:
                _instance_list.append(cls(*args, **kwargs))
            # 循环返回实例
            _instance_list.insert(0,_instance_list[-1])
            return _instance_list.pop()
        return _singleton
    return singleton


import pymongo

MONGODB_URL = ""
MONGODB_DATABASE = ""

@connection_pool(3)  # 将三个连接实例加入连接池中
class MongodbModule(object):
    def __init__(self,url = MONGODB_URL,db = MONGODB_DATABASE):
        self.myclient = pymongo.MongoClient(url)
        self.mydb = self.myclient[db]

# 循环返回mongodb的实例
mongo = MongodbModule()
上一篇 下一篇

猜你喜欢

热点阅读