python的单例模式

161 阅读2分钟

单例模式的介绍

概念

单例模式是一种设计模式,确保一个类只有一个实例,并提供全局访问点。简单来说,它的核心概念是:

  1. 唯一性:类只能创建一个实例。
  2. 全局访问:提供一个方法来访问这个唯一实例。

优点

  • 节省资源:避免了重复创建对象,减少了内存使用。
  • 全局状态管理:方便管理全局共享的数据或状态。

单例模式的多种实现方式

在 Python 中,可以使用多种方法实现单例模式。以下是几种常见的方法:

1. 使用类变量 通过类变量存储实例,确保只有一个实例被创建。

class Singleton:
    _instance = None

    def __new__(cls, *args, **kwargs):
        if not cls._instance:
            cls._instance = super(Singleton, cls).__new__(cls)
        return cls._instance


# 测试
singleton1 = Singleton()
singleton2 = Singleton()

print(singleton1 is singleton2)  # 输出: True

2. 使用装饰器 定义一个装饰器来包装类,确保只有一个实例。

def singleton(cls):
    instances = {}
    def get_instance(*args, **kwargs):
        if cls not in instances:
            instances[cls] = cls(*args, **kwargs)
        return instances[cls]
    return get_instance

@singleton
class Singleton:
    pass

# 测试
singleton1 = Singleton()
singleton2 = Singleton()

print(singleton1 is singleton2)  # 输出: True

3. 使用模块 Python 的模块本身就是单例的,因此可以简单地利用模块来实现单例模式。

# singleton.py
class Singleton:
    pass

singleton_instance = Singleton()

# 在其他地方导入
# from singleton import singleton_instance

4. 使用元类 通过元类控制类的实例化过程。

class SingletonMeta(type):
    _instances = {}

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


class Singleton(metaclass=SingletonMeta):
    pass


# 测试
singleton1 = Singleton()
singleton2 = Singleton()

print(singleton1 is singleton2)  # 输出: True

总结 以上方法各有优缺点:

  • 类变量法:简单直接,易于理解。
  • 装饰器法:灵活且可复用。
  • 模块法:简单,不需要额外的逻辑。
  • 元类法:较为复杂,但适用于需要更多控制的场景。 根据需要选择适合的实现方式。

多线程操作单例模式

可能出现的问题

如果缺乏适当的锁机制,一个线程可能已经创建了实例,但另一个线程仍可能进入实例化的逻辑,从而创建第二个实例。

import time
class Singleton:
    _instance = None

    def __new__(cls, *args, **kwargs):
        if cls._instance:
            return cls._instance
        
        # 模拟所有线程到这里停止
        time.sleep(0.1)
        cls._instance = super(Singleton, cls).__new__(cls)
        return cls._instance


def create_instance():
    obj = Singleton()
    print(f"Instance ID: {id(obj)}")


# 多线程模拟
import threading

# 创建多个线程
threads = []
for _ in range(10):
    thread = threading.Thread(target=create_instance)
    threads.append(thread)
    thread.start()

# 等待所有线程完成
for thread in threads:
    thread.join()

解决方法

使用锁:在创建实例时使用线程锁,确保同一时间只有一个线程可以进入创建逻辑。

Class singleton:
    _instance = None
    _lock = threading.Lock()  
    def __new__(cls, *args, **kwargs):
        
        if cls._instance :
            return cls._instance
        
        with cls._lock:  # 使用锁
            if not cls._instance:
                return super().__new__(cls,*args,**kwargs)
            return cls._instance