【python开发】并发编程(上)-七、单例模式(扩展)

时间:2024-04-14 17:10:13

单例模式(Singleton Pattern)是一种常用的软件设计模式,该模式的主要目的是确保某一个类只有一个实例存在。当你希望在整个系统中,某个类只能出现一个实例时,单例对象就能派上用场。

主要有四种实现方式:

  1. 模块实现方式:

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

  1. 装饰器实现方式。
  2. 类方法实现。
  3. 基于__new__ 方法实现:、

我们知道,当我们实例化一个对象时,是先执行了类的__new__方法(我们没写时,默认调用object.new),实例化对象;然后再执行类的__init__方法,对这个对象进行初始化,所以我们可以基于这个,实现单例模式。

class Singleton:

    instance = None

    def __init__(self, name):
        self.name = name

    def __new__(cls, *args, **kwargs):
        #返回空对象

        if cls.instance:
            print("已经有了")
            return cls.instance
        else:
            print("还没有")
            cls.instance = object.__new__(cls)

        return cls.instance


obj1 = Singleton("alex")
obj2 = Singleton("nihao")

print(obj1, obj2)
'''
还没有
已经有了
<__main__.Singleton object at 0x7fa5ce9417f0> <__main__.Singleton object at 0x7fa5ce9417f0>

'''

从上述实验可以看出,通过__new__方法实现单例模后,实例化的对象调用了同一个内存。但是该方法不适用多线程,应为再多线程条件下,由于cpu分区执行,可能占据不同的内存保存对象。

class Singleton:

    instance = None

    def __init__(self, name):
        self.name = name

    def __new__(cls, *args, **kwargs):
        #返回空对象

        if cls.instance:
            #print("已经有了")
            return cls.instance
        time.sleep(0.1)
        #print("还没有")
        cls.instance = object.__new__(cls)

        return cls.instance



def task():
    obj = Singleton('x')
    print(obj)


for i in range(10):
    t = threading.Thread(target=task)
    t.start()


'''
<__main__.Singleton object at 0x7fa11ba419d0><__main__.Singleton object at 0x7fa11d118fd0>
<__main__.Singleton object at 0x7fa11d0fefd0>
<__main__.Singleton object at 0x7fa11d1184c0>

<__main__.Singleton object at 0x7fa11b86caf0>
<__main__.Singleton object at 0x7fa11b86c850>
<__main__.Singleton object at 0x7fa11b86c730>
<__main__.Singleton object at 0x7fa11b86caf0>
<__main__.Singleton object at 0x7fa11b86c850>
<__main__.Singleton object at 0x7fa11b8868e0>
'''

针对这一个问题,同样可以用RLock来解决:

class Singleton:

    instance = None
    lock = threading.RLock()

    def __init__(self, name):
        self.name = name

    def __new__(cls, *args, **kwargs):
        #返回空对象

        if cls.instance:
            return cls.instance
        cls.instance = object.__new__(cls)

        with cls.lock:
            if cls.instance:
                return cls.instance
            time.sleep(1)
            cls.instance = object.__new__(cls)

        return cls.instance



def task():
    obj = Singleton('x')
    print(obj)


for i in range(10):
    t = threading.Thread(target=task)
    t.start()


'''
<__main__.Singleton object at 0x7fb7166d5910>
<__main__.Singleton object at 0x7fb7166d5910>
<__main__.Singleton object at 0x7fb7166d5910>
<__main__.Singleton object at 0x7fb7166d5910>
<__main__.Singleton object at 0x7fb7166d5910>
<__main__.Singleton object at 0x7fb7166d5910>
<__main__.Singleton object at 0x7fb7166d5910>
<__main__.Singleton object at 0x7fb7166d5910>
<__main__.Singleton object at 0x7fb7166d5910>
<__main__.Singleton object at 0x7fb7166d5910>
'''