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

一、使用__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

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值