mysql 单态设计模式_设计模式之单例模式

什么是总线

总线(Bus)是计算机各种功能部件之间传送信息的公共通信干线,它是由导线组成的传输线束, 按照计算机所传输的信息种类,计算机的总线可以划分为数据总线、地址总线和控制总线,分别用来传输数据、数据地址和控制信号。总线是一种内部结构,它是cpu、内存、输入、输出设备传递信息的公用通道,主机的各个部件通过总线相连接,外部设备通过相应的接口电路再与总线相连接,从而形成了计算机硬件系统。在计算机系统中,各个部件之间传送信息的公共通路叫总线,微型计算机是以总线结构来连接各个功能部件的。

现假设有如下场景:某中央处理器(CPU)通过某种协议总线与一个信号灯相连,信号灯有64种颜色可以设置,中央处理器上运行着三个线程,都可以对这个信号灯进行控制,并且可以独立设置该信号灯的颜色。抽象掉协议细节(用打印表示),如何实现线程对信号等的控制逻辑。

首先我们应该想到的是加线程锁进行控制,确保信号灯顺序的安全性,但是加线程锁之后很显然加大了线程之间的耦合性,所以这里我们就想到了使用单例模式。即有且只有一个实例,若之后还实例改对象的话直接取出,个人认为与缓冲机制有异曲同工之妙,代码实现如下:

from threading import Thread,RLock

import time

#这里使用方法__new__来实现单例模式

class Singleton(object):#抽象单例

#1、 用hasattr判断

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

if not hasattr(cls, '_instance'):

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

return cls._instance

# 2、用if判断

# _instance = None

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

# if cls._instance is None:

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

# return cls._instance

#总线

class Bus(Singleton):

lock = RLock()

def sendData(self,data):

self.lock.acquire()

time.sleep(3)

print("Sending Signal Data...",data)

self.lock.release()

#线程对象,为更加说明单例的含义,这里将Bus对象实例化写在了run里

class VisitEntity(Thread):

my_bus=""

name=""

def getName(self):

return self.name

def setName(self, name):

self.name=name

def run(self):

self.my_bus=Bus()

self.my_bus.sendData(self.name)

if __name__=="__main__":

for i in range(3):

print("Entity %d begin to run..."%i)

my_entity=VisitEntity()

my_entity.setName("Entity_"+str(i))

my_entity.start()

单例模式

什么是单例模式

定义:Ensure a class has only one instance, and provide a global point of access to it.

通俗理解:保证某一个类只有一个实例,而且在全局只有一个访问点

为什么要用单例模式

优点:

1、由于单例模式要求在全局内只有一个实例,因而可以节省比较多的内存空间;

2、全局只有一个接入点,可以更好地进行数据同步控制,避免多重占用;

3、单例可长驻内存,减少系统开销。

缺点:

1、单例模式的扩展是比较困难的;

2、赋于了单例以太多的职责,某种程度上违反单一职责原则(六大原则后面会讲到);

3、单例模式是并发协作软件模块中需要最先完成的,因而其不利于测试;

4、单例模式在某种情况下会导致“资源瓶颈”

应用:

1、生成全局惟一的序列号;

2、访问全局复用的惟一资源,如磁盘、总线等;

3、单个对象占用的资源过多,如数据库等;

4、系统全局统一管理,如Windows下的Task Manager;

5、网站计数器。

实现单例模式的几种方式

通过模块来实现

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

通过类方法实现单例模式

class Mysql:

__instance = None

def __init__(self,ip,port):

self.ip = ip

self.port = port

@classmethod

def singleton(cls):

if cls.__instance:

return cls.__instance

cls.__instance = cls('127.0.0.1',8080)

return cls.__instance

obj1 = Mysql('111,111,111,0',8080)

obj2 = Mysql('222,222,222,0',8080)

print(obj1)

print(obj2)

obj3 = Mysql.singleton()

obj4 = Mysql.singleton()

print(obj3,obj4)

通过元类实现单例模式

class Mymeta(type):

def __init__(self,class_name,class_bases,class_dict):

self.__instance = object.__new__(self)

self.__init__(self.__instance,'127.0.0.1',8080)

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

if args or kwargs:

obj = object.__new__(self)

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

return obj

else:return self.__instance

class Mysql(metaclass=Mymeta):

def __init__(self,ip,port):

self.ip = ip

self.port = port

obj1 = Mysql("1.1.1.1", 3306)

obj2 = Mysql("1.1.1.2", 3306)

print(obj1)

print(obj2)

obj3 = Mysql()

obj4 = Mysql()

print(obj3 is obj4)

通过装饰器实现单例模式

def single_func(func):

_instance = func('127.0.0.1',8080)

def inner(*args,**kwargs):

if args or kwargs:

res = func(*args,**kwargs)

return res

else:

return _instance

return inner

@single_func

class Mysql:

def __init__(self,ip,port):

self.ip = ip

self.port = port

obj1 = Mysql("1.1.1.1", 3306)

obj2 = Mysql("1.1.1.2", 3306)

print(obj1)

print(obj2)

obj3 = Mysql()

obj4 = Mysql()

print(obj3 is obj4)

通过__new__方法实现

class Mysql:

__instance=None

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

if cls.__instance is None:

obj = object.__new__(cls)

cls.__instance = obj

return cls.__instance

obj1 = Mysql()

obj2 = Mysql()

print(obj1)

print(obj2)

进阶必会

本部分主要是补充介绍多线程并发情况下,多线程高并发时,如果同时有多个线程同一时刻(极端条件下)事例化对象,那么就会出现多个对象,这就不再是单例模式了。

解决这个多线程并发带来的竞争问题,第一个想到的是加互斥锁,于是我们就用互斥锁的原理来解决这个问题。

解决的关键点,无非就是将具体示例化操作的部分加一把锁,这样同时来的多个线程就需要排队。

这样一来只有第一个抢到锁的线程实例化一个对象并保存在_instance中,同一时刻抢锁的其他线程再抢到锁后,不会进入这个判断if not cls._instance,直接把保存在_instance的对象返回了。这样就实现了多线程下的单例模式。

此时还有一个问题需要解决,后面所有再事例对象时都需要再次抢锁,这会大大降低执行效率。解决这个问题也很简单,直接在抢锁前,判断下是否有单例对象了,如果有就不再往下抢锁了(代码第11行判断存在的意义)。

import threading

class Student:

_instance = None# 保存单例对象

_lock = threading.RLock() # 锁

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

if cls._instance:# 如果已经有单例了就不再去抢锁,避免IO等待

return cls._instance

with cls._lock:# 使用with语法,方便抢锁释放锁

if not cls._instance:

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

return cls._instance

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值