16.python-单例模式

python-单例模式

单例模式适用于需要共享对象的场景

单例模式,也叫单子模式,是一种常用的软件设计模式。在应用这个模式时,单例对象的类必须保证只有一个实例存在。许多时候整个系统只需要拥有一个的全局对象,这样有利于我们协调系统整体的行为。比如在某个服务器程序中,该服务器的配置信息存放在一个文件中,这些配置数据由一个单例对象统一读取,然后服务进程中的其他对象再通过这个单例对象获取这些配置信息

  1. 单例模式是一种软件设计模式,而不是专属于某种编程语言的语法;
  2. 单例模式只有一个实例存在;
  3. 单例模式有助于协调系统的整体性、统一性;
  4. 每一次执行 类名() 返回的对象,内存地址是相同

优点:

1、在内存里只有一个实例,减少了内存的开销,尤其是频繁的创建和销毁实例

2、避免对资源的多重占用(比如写文件操作)

应用场景

  1. 资源共享的情况下,避免由于资源操作时导致的性能或损耗等。如日志文件,应用配置。
  2. 控制资源的情况下,方便资源之间的互相通信。如线程池等。

实现1-使用__new__

class Singleton:
    __instance = None  # 类属性,用于保存唯一的实例

    def __new__(self):
        if self.__instance is None:
            self.__instance = object.__new__(self)

        return self.__instance

s1 = Singleton()
s2 = Singleton()

print(s1)
print(s2)

# 执行结果
<__main__.Singleton object at 0x105149550>
<__main__.Singleton object at 0x105149550>

多线程加锁

import threading

class Singleton(object):
    _instance_lock = threading.Lock()

    def __init__(self):
        pass


    def __new__(cls, *args, **kwargs):
        if not hasattr(Singleton, "_instance"):
            with Singleton._instance_lock:
                if not hasattr(Singleton, "_instance"):
                    Singleton._instance = object.__new__(cls)  
        return Singleton._instance

obj1 = Singleton()
obj2 = Singleton()
print(obj1,obj2)

实现2-元类继承

元类是一种特殊的Python类,它可以用来创建其他类。使用元类可以将一个类转换为单例模式,后面我们会介绍元类

class Singleton(type):
    _instances = {}

    def __call__(cls, *args, **kwargs):
        if cls not in cls._instances:
            cls._instances[cls] = object.__call__(*args, **kwargs)
        return cls._instances[cls]


class MyClass(metaclass=Singleton):
    pass

class MyClass2(metaclass=Singleton):
    pass


c1 = MyClass()
c2 = MyClass()
c3 = MyClass2()
c4 = MyClass2()

print(c1)
print(c2)
print(c3)
print(c4)
# 执行结果
<object object at 0x100cd9df0>
<object object at 0x100cd9df0>
<object object at 0x100cd9e40>
<object object at 0x100cd9e40>

多线程模式下的单例模式

# -*- coding: utf-8 -*-
import threading

def Singleton(cls):
    # print("log singleton")
    cls._instance = None
    cls._lock = threading.Lock()

    def __new__(*args, **kwargs): 
        # print(f"log new", args, kwargs)     # 实际上args中也包含cls和相关的参数
        with cls._lock:
            if not cls._instance:
                cls._instance = object.__new__(cls)
        return cls._instance

    cls.__new__ = __new__
    return cls


@Singleton
class T:
    def __init__(self, a):
        self.a = a

def task(a):
    s = T(a)
    print(s)

def helper():
    for i in range(5):
        t = threading.Thread(target=task, args=(2,))
        t.start()


if __name__ == '__main__':
    helper()


实现3-函数装饰器实现

def singleton(cls):
    instances = {}

    def wrapper(*args, **kwargs):
        if cls not in instances:
            instances[cls] = cls(*args, **kwargs)
        return instances[cls]

    return wrapper


@singleton
class MyClass:
    pass


@singleton
class MyClass2:
    pass


c1 = MyClass()
c2 = MyClass()
c3 = MyClass2()
c4 = MyClass2()

print(c1)
print(c2)
print(c3)
print(c4)
# 执行结果
<__main__.MyClass object at 0x103419fa0>
<__main__.MyClass object at 0x103419fa0>
<__main__.MyClass2 object at 0x103419cd0>
<__main__.MyClass2 object at 0x103419cd0>

实现4-类方法

class Singleton(object):

    def __init__(self):
        pass

    @classmethod
    def instance(cls, *args, **kwargs):
        if not hasattr(Singleton, "_instance"):
            Singleton._instance = Singleton(*args, **kwargs)
        return Singleton._instance

但是当使用多线程时会存在问题,按照以上方式创建的单例,无法支持多线程。

import time
import threading

class Singleton(object):
    _instance_lock = threading.Lock()

    def __init__(self):
        time.sleep(1)

    @classmethod
    def instance(cls, *args, **kwargs):
        if not hasattr(Singleton, "_instance"):
            with Singleton._instance_lock:
                if not hasattr(Singleton, "_instance"):
                    Singleton._instance = Singleton(*args, **kwargs)
        return Singleton._instance


def task(arg):
    obj = Singleton.instance()
    print(obj)
    
    
for i in range(10):
    t = threading.Thread(target=task,args=[i,])
    t.start()
    
    
time.sleep(20)
obj = Singleton.instance()
print(obj)

实现5-直接导入

class Singleton(object):
    def foo(self):
        pass
singleton = Singleton()

将上面的代码保存在文件其他文件中,要使用时,直接在其他文件中导入此文件中的对象,这个对象即是单例模式的对象

from mysingleton import singleton

Note

单例在单线程模型下,是线程安全的,不管怎么样创建实例,都有且只有一个,而面对多线程任务时,一般的单例代码无法承担多线程任务,当有io延时操作时,会生成id不同的实例,所以如果需要实现多线程单例,那么就在创建实例时增加线程锁

posted @ 2023-07-01 08:40  贝壳里的星海  阅读(45)  评论(0编辑  收藏  举报