python单例模式数据库连接失败_python的单例模式--解决多线程的单例模式失效

单例模式

单例模式(Singleton Pattern)

是一种常用的软件设计模式,主要目的是确保某一个类只有一个实例存在。希望在整个系统中,某个类只能出现一个实例时,单例对象就能派上用场

比如,某个服务器程序的配置信息存放在一个文件中,客户端通过一个 AppConfig 的类来读取配置文件的信息。如果在程序运行期间,有很多地 方都需要使用配置文件的内容,也就是说,很多地方都需要创建 AppConfig 对象的实例,这就导致系统中存在多个 AppConfig 的实例对象,而这样 会严重浪费内存资源,尤其是在配置文件内容很多的情况下。事实上,类似 AppConfig 这样的类,我们希望在程序运行期间只存在一个实例对象。

使用需求: 程序运行起来 只需要一份

比如:admin的register

数据库连接,数据库连接池

(全局变量)

全局变量 --- 模块导入 (使用同一个数据)

单例模式

单例模式的应用---数据库连接池

class SingleDBpool(object):

def __init__(self):

self.pool = ...

def __new__(cls, *args, **kwargs):

if not hasattr(cls,'_instance'):

cls._instance = super(SingleDBpool,cls).__new__(*args, **kwargs)

return cls._instance

def connect(self):

return self.pool.connection()

Python 中,单例模式的实现:

1 使用模块

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

# mysingleton.py

class My_Singleton(object):

def foo(self):

pass

my_singleton = My_Singleton()

将上面的代码保存在文件 mysingleton.py 中,然后这样使用:

from mysingleton import my_singleton

my_singleton.foo()

2 使用 new

为了使类只能出现一个实例,我们可以使用 new 来控制实例的创建过程,代码如下:

class Singleton(object):

_instance = None

def __new__(cls, *args, **kw):

if not cls._instance:

cls._instance = super(Singleton, cls).__new__(cls, *args, **kw)

return cls._instance

class MyClass(Singleton):

a = 1

3 使用类方法 但是每次调用会很繁琐 A.get_instance(params) -- 无法支持多线程

class A(object):

instance = None

def __init__(self,name):

self.name = name

@classmethod

def get_instance(cls,*args,**kwargs):

if not cls.instance:

cls.instance = cls(*args,**kwargs)

return cls.instance

a = A.get_instance('aaa')

b = A.get_instance('bbb')

print(a.name)

多线程下,为什么会失效?

import threading

class Single(object):

instance = None

def __init__(self):

import time

time.sleep(0.5) # 有延时的情况

pass

@classmethod

def get_instance(cls,*args,**kwargs):

if not cls.instance:

cls.instance = cls(*args,**kwargs)

return cls.instance

def task(arg):

obj = Single.get_instance()

print(obj)

for i in range(5):

t = threading.Thread(target=task,args=[i,])

t.start()

结果:创建了不同的对象 -- 失效

# <__main__.Single object at 0x00000000029B8F60>

# <__main__.Single object at 0x00000000029B8E80>

# <__main__.Single object at 0x000000000299BD68>

# <__main__.Single object at 0x00000000029F2BE0>

# <__main__.Single object at 0x00000000029C2B38>

如何解决多线程下单例的失效

>> 加线程锁

import threading

import time

class Single(object):

instance = None

_threading_lock = threading.Lock()

def __init__(self):

time.sleep(0.5)

@classmethod

def get_instance(cls,*args,**kwargs):

if not cls.instance: # 先判断是否存在(如果存在,说明不是多线程,直接获取)

with cls._threading_lock: # 加锁,只有一个线程进入,然后判断 单例是否存在

if not cls.instance: # 先判断是否存在(如果存在,说明不是多线程,直接获取)

cls.instance = cls(*args,**kwargs)

return cls.instance

return cls.instance

def task(arg):

obj = Single.get_instance()

print(obj)

for i in range(5):

t = threading.Thread(target=task,args=[i,])

t.start()

time.sleep(5)

obj = Single.get_instance()

print(obj)

4 使用装饰器

可以使用装饰器来装饰某个类,使其只能生成一个实例

def Singleton(cls):

instance = []

def inner(*args,**kwargs):

if cls(*args,**kwargs) not in instance:

instance.append(cls(*args,**kwargs))

return instance[0]

return inner

@Singleton

class A(object):

pass

a = A()

b = A()

print(a == b)

5 使用 metaclass

对象和类创建的 完整流程 :

class F:

pass

1 执行type的 init 方法(类是type的对象)

obj = F()

2 执行type的 call 方法

2.1 调用 F类的 new 方法 (创建对象)

2.2 调用 F类的 init 方法 (对象初始化)

obj()

3 执行 F的 call 方法

# 继承 type 类(模拟重写 type -- 用于创建类)

class Single(type):

def __init__(self,*args,**kwargs):

super(Single,self).__init__(*args,**kwargs)

def __call__(cls, *args, **kwargs):

obj = cls.__new__(cls,*args, **kwargs)

cls.__init__(obj,*args, **kwargs)

return obj

# 用伪type 创建Foo类

class Foo(metaclass=Single): # 通过 Single 创建

def __init__(self,name):

self.name= name

def __new__(cls, *args, **kwargs):

return object.__new__(cls,*args, **kwargs)

元类(metaclass)可以控制类的创建过程,它主要做三件事:

拦截类的创建

修改类的定义

返回修改后的类

使用元类实现单例模式:

class Single(type): # 通过

def __call__(cls, *args, **kwargs):

if not hasattr(cls,'_instance'):

cls._instance = cls.__new__(cls,*args, **kwargs)

return cls._instance

class Foo(metaclass=Single): # 通过 Single 创建

pass

这样 通过创建Single类,以后需要单例模式的类,可以指定 用 它来创建就可以了

Python 的模块是天然的单例模式,这在大部分情况下应该是够用的,也可以使用装饰器、元类等方法

metaclass补充

class MyType(type):

def __init__(self, *args, **kwargs):

super(MyType, self).__init__(*args, **kwargs)

def __call__(cls, *args, **kwargs):

return super(MyType, cls).__call__(*args, **kwargs)

def with_metaclass(base):

return MyType('XX', (base,), {})

class Foo(with_metaclass(object)):

pass

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值