Python 实现单例模式的几种方式以及存在的问题

Python 实现单例模式的几种方式以及存在的问题,第1张


一、使用__new__方法:

import threading
import time

class SingleClass:
    _instance = None
    
    def __new__(cls, *args, **kwargs):
        if cls._instance is None:
            cls._instance = object.__new__(cls, *args, **kwargs)
        return cls._instance
    
    def __init__(self):
        pass
    
 

二、并发单例:

存在线程安全问题,可能多个线程同时执行到创建_instance语句。


import threading
import time

class SingleClass:
    _instance = None
    
    def __new__(cls, *args, **kwargs):
        if cls._instance is None:
            time.sleep(1)
            cls._instance = object.__new__(cls, *args, **kwargs)
        return cls._instance
    
    def __init__(self):
        pass
    

def get_single():
    print(SingleClass())

    
threading.Thread(target=get_single).start()
threading.Thread(target=get_single).start()

运行结果:

<__main__.SingleClass object at 0x000001FA63C71DF0><__main__.SingleClass object at 0x000001FA62D49C40>

可以看到产生了两个不同的对象。


解决方法:

在__new__中使用线程锁保证线程安全。


import threading
import time

class SingleClass:
    _instance_lock = threading.Lock()
    _instance = None
    
    def __new__(cls, *args, **kwargs):
        with cls._instance_lock:
            if cls._instance is None:
                cls._instance = object.__new__(cls, *args, **kwargs)
        return cls._instance
    
    def __init__(self):
        pass
   
 
def get_single():
    print(SingleClass())
    
    
threading.Thread(target=get_single).start()
threading.Thread(target=get_single).start()

若要在多进程中实现单例,则必须使用多进程模块中的共享资源实现。


个人猜测是因为多进程全局变量不共享导致单例失效,欢迎明白的大佬指点。


import multiprocessing
from multiprocessing import Process, Queue


class SingleClass:
    def __init__(self, a):
        self.a = a


def get_single(d, lock, a):
    lock.acquire()
    if d.get('single', None) is None:
        d['single'] = SingleClass(a)
    lock.release()
    print(d['single'].a)


if __name__ == '__main__':
    m = multiprocessing.Manager()
    d = m.dict()
    lock = multiprocessing.Lock()
    t = Process(target=get_single, args=(d, lock, 1))
    t1 = Process(target=get_single, args=(d, lock, 2))
    t.start()
    t1.start()
    t.join()
    t1.join()


三、使用metaclass

class SingleClass(type):
    _instance_lock = threading.Lock()
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self._instance = None
    
    def __call__(self, *args, **kwargs):
        with self._instance_lock:
            if self._instance is None:
                self._instance = super().__call__(*args, **kwargs)
        return self._instance

    
class SubClass1(metaclass=SingleClass):
    pass

四、使用装饰器

import threading
import time

def single(cls):
    instance = None
    instance_lock = threading.Lock()
    def inner(*args, **kwargs):
        nonlocal instance
        with instance_lock:
            if instance is None:
                instance = cls(*args, **kwargs)
        return instance
    return inner

@single
class SingleClass():
    pass

欢迎分享,转载请注明来源:内存溢出

原文地址: http://www.outofmemory.cn/langs/569753.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-04-09
下一篇 2022-04-09

发表评论

登录后才能评论

评论列表(0条)

保存