将线程安全单例Python类作为可导入模块以在其他模块之间重用时出错

问题描述 投票:0回答:1

问题

我一直在尝试创建一个线程安全的SingletonClass作为模块,可以通过导入为模块来重用在其他python脚本中。更像import and use it作为要使其成为单例的类的元类。

但是,但是当我运行程序时,我陷入了僵局,其他导入模块的类都在等待在他们之前有人用它作为元类来发布。我了解我可能缺少与导入和名称空间相关的大量python基础知识,这就是我无法理解这一点的原因。我之前一般都阅读过以下有关单例的文章,但我认为这个问题与导入有关,而不是其他任何问题。

链接:Creating a singleton in Python

如果有人可以指出这个错误并提供一种可能的方法使其成为可重用的模块,或者提供可以帮助我解决此问题的外部文章的链接,那将是很好的。让我知道我的想法是可行的还是有缺陷的。这确实有助于正确理解基本知识。

下面给出我的文件夹结构和相应的代码。

以下是我的文件夹结构,每个文件中都有相应的代码。

.
├── A.py
├── B.py
├── C.py
└── ThreadSafeSingleton.py

0 directories, 4 files

[代码] >>

ThreadSafeSingleton.py

        import threading
        import logging

        logger= logging.getLogger(__name__)


        class ThreadSafeSingletonClass(type):
            # Taken from: https://stackoverflow.com/a/51897195 :)
            _instances = {}
            _singleton_lock = threading.Lock()
            def __call__(cls, *args, **kwargs):
                # double-checked locking pattern
                logger.error("ThreadSafeSingletonClass : Inside __call__ of ThreadSafeSingleton")
                logger.error("ThreadSafeSingletonClass : Called By"+str(cls))
                if cls not in cls._instances:
                    logger.error("ThreadSafeSingletonClass : Trying to get lock")
                    with cls._singleton_lock:
                        logger.error("ThreadSafeSingletonClass : Got lock")
                        if cls not in cls._instances:
                            logger.error("ThreadSafeSingletonClass : Object of type" + str(cls) + " being Created")
                            cls._instances[cls] = super(ThreadSafeSingletonClass, cls).__call__(*args, **kwargs)
                logger.error("ThreadSafeSingletonClass : Returning created Instance"+str(cls))
                return cls._instances[cls]

A.py

        import logging 
        from ThreadSafeSingleton import ThreadSafeSingletonClass
        from B import B

        logger=logging.getLogger(__name__)
        logger.setLevel(logging.DEBUG)

        class A(metaclass = ThreadSafeSingletonClass):
            def __init__(self):
                logger.error("A : Inside init of A")
                logger.error("A : Creating object of B")
                b=B()

        logger.error("A: Creating object of A as part of main")
        A()
        logger.error("A: Returned back to A now")
        logger.error("A: Exiting...")

B.py


        from ThreadSafeSingleton import ThreadSafeSingletonClass

        import C
        import logging

        logger = logging.getLogger(__name__)

        class B(metaclass=ThreadSafeSingletonClass):
            def __init__(self):
                logger.error("B: Inside Init of B")
                logger.error("B: Trying to create object of C")
                c=C.C()

C.py

        from ThreadSafeSingleton import ThreadSafeSingletonClass

        class C(metaclass = ThreadSafeSingletonClass):
            def __init__(self):
                logger.error("C: We are at C Object")

[输出

(env) duplex@Test:~/test/Test$ python A.py 
A: Creating object of A as part of main
ThreadSafeSingletonClass : Inside __call__ of ThreadSafeSingleton
ThreadSafeSingletonClass : Called By<class '__main__.A'>
ThreadSafeSingletonClass : Trying to get lock
ThreadSafeSingletonClass : Got lock
ThreadSafeSingletonClass : Object of type<class '__main__.A'> being Created
A : Inside init of A
A : Creating object of B
ThreadSafeSingletonClass : Inside __call__ of ThreadSafeSingleton
ThreadSafeSingletonClass : Called By<class 'B.B'>
ThreadSafeSingletonClass : Trying to get lock

它被卡在那里。我无法理解,因为A是一个单独的单例,而B是一个单独的单例,为什么创建B对象依赖于其他人来释放锁?如果这不是正确的方法,那么如何实现Singleton类成为可重用模块的目标。

目标

目的是将单例元类作为模块,这样,任何想要实现单例的类都必须将其作为其模块的一部分导入,并将其用作元类,而不是每次在每个模块文件中都定义该类。

背景

我正在学习设计模式,并且一直在研究Python中的Singleton模式。目前,我正在尝试在模块中定义一个线程安全单例元类,而该模块又应该导入被其他类作为自己的元类。

问题,我一直在尝试创建一个线程安全的SingletonClass作为模块,可以通过将其作为其他python脚本中的模块导入来重用。更像import并将其用作...

python python-3.x singleton python-import
1个回答
0
投票

您在ThreadSafeSingleton.__call__内部,直到A()返回对象。因此,如果您将此函数嵌套在另一个调用中,则必须为每个类使用单独的锁。

© www.soinside.com 2019 - 2024. All rights reserved.