python3 单例模式 使用线程池_浅谈单例模式及其应用场景(Python)

使用场景:

Python的logger就是一个单例模式,用以日志记录

Windows的资源管理器是一个单例模式

线程池,数据库连接池等资源池一般也用单例模式

网站计数器

从这些使用场景我们可以总结下什么情况下需要单例模式:

1. 当每个实例都会占用资源,而且实例初始化会影响性能,这个时候就可以考虑使用单例模式,它给我们带来的好处是只有一个实例占用资源,并且只需初始化一次;

当有同步需要的时候,可以通过一个实例来进行同步控制,比如对某个共享文件(如日志文件)的控制,对计数器的同步控制等,这种情况下由于只有一个实例,所以不用担心同步问题。

1. 模块即单利

常见的场景即logging模块,写好一个日志类模块后,并实例化一个logger, 整个项目就调用这个logger

// logging_module.py

class LoggerMgr(object):

def foo(self):

pass

mylogger = LoggerMgr()

2. __new__方法实现

class Singleton(object):

__instance = None

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

if cls.__instance is None:

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

# 可以在这里给实力对象绑定一些固有属性

# cls.__instance.appkey = ""

return cls.__instance

class Singleton(object):

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

# 判断是否存在类属性_instance,_instance是类CCP的唯一对象,即单例

if not hasattr(Singleton, "__instance"):

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

# cls.__instance = object.__new__(cls)

return cls.__instance

但是以上的方法在多线程中会有线程安全问题,当有多个线程同时去初始化对象时,就很可能同时判断__instance is None,从而进入初始化instance的代码中(如果有__init__方法)。所以需要用互斥锁来解决这个问题。

3. 使用装饰器来获取单例对象

# 装饰器(decorator)可以动态地修改一个类或函数的功能

import functools

def singleton(cls):

__instance = {}

@functools.wraps(cls)

def getinstance(*args, **kwargs):

if cls not in __instance:

__instance[cls] = cls(*args, **kwargs)

return __instance[cls]

return getinstance

@singleton

class MyClass(object):

a = 1

我们定义了一个装饰器 singleton,它返回了一个内部函数 getinstance,该函数会判断某个类是否在字典 instances 中,如果不存在,则会将 cls 作为 key,cls(*args, **kw) 作为 value 存到 instances 中,否则,直接返回 instances[cls]。

4. 使用metaclass元类创建单例

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

拦截类的创建

修改类的定义

返回修改后的类

class Singleton(type):

__instances = {}

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

if cls not in cls.__instances:

cls.__instances[cls] = super(Singleton, cls).__call__(*args, **kwargs)

return cls.__instances[cls]

# python2写法

# class MyClass(object):

# __metaclass__ = Singleton()

# python3写法

class MyClass(metaclass=Singleton):

def __init__(self):

self.blog = "blog"

5. 线程安全单利模式

import threading

def make_synchronized(func):

import threading

func.__lock__ = threading.Lock()

# 用装饰器实现同步锁

def synced_func(*args, **kwargs):

with func.__lock__:

return func(*args, **kwargs)

return synced_func

class Singleton(object):

__instance = None

@make_synchronized

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

if not cls.__instance:

cls.__instance = object.__new__(cls)

return cls.__instance

def __init__(self):

self.blog = "blog"

# -------------

def worker():

e = Singleton()

print(id(e))

def meta():

e1 = Singleton()

e2 = Singleton()

e1.blog = 123

print(e1.blog)

print(e2.blog)

print(id(e1))

print(id(e2))

if __name__ == "__main__":

meta()

tasks = [threading.Thread(target=worker) for _ in range(20)]

for task in tasks:

task.start()

task.join()

6. 元编程线程安全的单利模式

import threading

class MetaSingleton(type):

_instance_lock = threading.Lock()

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

if not hasattr(cls, '_instance'):

with MetaSingleton._instance_lock:

if not hasattr(cls, '_instance'):

cls._instance = super(MetaSingleton, cls).__call__(*args, **kwargs)

return cls._instance

class Singleton(metaclass=MetaSingleton):

def __init__(self, name):

self.name = name

7. 参考文献

你可能感兴趣的:(python3,单例模式,使用线程池)