python单例模式

1. 什么是单例模式

单例模式是一种常见的软件设计模式。主要是确保一个类只有一个实例存在。单例模式可以节约系统资源

2. 常见应用场景

3.  实现单例模式的方法

3.1 __new__方法

class Animal(object):

    instance = None

    @staticmethod
    def __new__(cls, *args, **kwargs):
        if not cls.instance:
            cls.instance = super(Animal, cls).__new__(cls)
        return cls.instance


dog = Animal()
cat = Animal()
print(id(dog))
print(id(cat))

3.2  装饰器

def singleton(cls):
    """单例模式装饰器"""
    instance = {}

    def get_instance():
        if cls not in instance:
            instance[cls] = cls()
        return instance[cls]

    return get_instance


@singleton
class Animal(object):
    def __init__(self):
        pass

3.3  使用元类

class Animal(type):
    """使用元类实现单例模式"""
    instance = None

    def __call__(cls):
        if not cls.instance:
            cls.instance = super(Animal, cls).__call__()
        return cls.instance


class Dog(metaclass=Animal):
    pass

3.4 使用模块

创建一个类的实例,然后在其他文件里import进去。

3.5 使用类创建单例模式

class Animal(object):
    """使用元类实现单例模式"""
    def __init__(self):
        pass

    @staticmethod
    def get_instance():
        if not hasattr(Animal, "_instance"):
            Animal._instance = Animal()
        return Animal._instance


def create_singleton():
    small_animal = Animal.get_instance()
    print(id(small_animal))


create_singleton()
create_singleton()

注:这样的单例模式在单线程下是安全的,但是如果遇到多线程,就会出现问题。示例代码如下:

import time
from concurrent.futures import ThreadPoolExecutor


class Animal(object):
    """使用元类实现单例模式"""
    def __init__(self):
        time.sleep(1)
        pass

    @staticmethod
    def get_instance():
        if not hasattr(Animal, "_instance"):
            Animal._instance = Animal()
        return Animal._instance


def create_singleton():
    small_animal = Animal.get_instance()
    print(id(small_animal))


if __name__ == "__main__":
    with ThreadPoolExecutor(max_workers=10) as executor:
        for i in range(10):
            executor.submit(create_singleton)

运行结果如下图所示,创建了10个实例。

 

 

 解决:加锁。在在获取对象属性_instance的时候加锁,加锁后的代码如下:

import time
from concurrent.futures import ThreadPoolExecutor
import threading


class Animal(object):
    """使用元类实现单例模式"""
    _lock = threading.Lock()

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

    @staticmethod
    def get_instance():
        if not hasattr(Animal, "_instance"):
            with Animal._lock:
                if not hasattr(Animal, '_instance'):
                    Animal._instance = Animal()
        return Animal._instance


def create_singleton():
    small_animal = Animal.get_instance()
    print(id(small_animal))


if __name__ == "__main__":
    with ThreadPoolExecutor(max_workers=10) as executor:
        for i in range(10):
            executor.submit(create_singleton)

 

posted @ 2020-06-14 22:36  theshy1103  阅读(148)  评论(0编辑  收藏  举报