创建单例队列Python

时间:2017-06-30 10:13:10

标签: python multithreading queue singleton

我在项目中创建了一堆组件,每个组件都在不同的线程中运行 他们将通过queue.Queue进行沟通。我想定义所有不同的队列,这是扩展queue.Queue的类。它们中的每一个都是单例对象,因此不同的组件可以只导入该类,并获取实例。

我将所有内容都放在一个文件中:

from queue import Queue

class QueueAudio(Queue):

    def __new__(cls, *args, **kwargs):
        """
        Singleton Queue
        """
        if '_inst' not in vars(cls):
            cls._inst = object.__new__(cls, *args, **kwargs)
            print('Creating {}'.format(cls.__name__))
        return cls._inst

class AudioInput(object):

    def __init__(self):
        self.queue = QueueAudio()
        print(self.queue)

    def run(self):
        self.queue.put('Input Audio')


class Interpretor(object):

    def __init__(self):
        self.queue = QueueAudio()
        print(self.queue)

    def run(self):
        print(self.queue.get())

audio = AudioInput()
audio.run()
interpretor = Interpretor()
interpretor.run()

在两个组件(AudioInputInterpretor)的构造函数中,我打印对象,以确保它们是相同的。 AudioInput在队列中放入一个字符串,Interpretor读取它。但是,Interpretor中的队列始终为空,使程序永远挂起。 这是该计划的输出:

Creating QueueAudio
<__main__.QueueAudio object at 0x103234c18>
<__main__.QueueAudio object at 0x103234c18>

3 个答案:

答案 0 :(得分:2)

我通过使用另一种方法将我的类定义为单例来解决我的问题:

class Singleton(type):
    _instances = {}
    def __call__(cls, *args, **kwargs):
        if cls not in cls._instances:
            cls._instances[cls] = super().__call__(*args, **kwargs)
        return cls._instances[cls]

class QueueAudio(Queue, metaclass=Singleton):
    pass

答案 1 :(得分:2)

这里发生的事情是,在__new__函数返回队列对象后,python会在其上隐式调用__init__。这将重置队列,并删除您之前添加的任何项目。

来自docs on __new__

  

如果__new__()返回cls的实例,则返回新实例   __init__()方法将被调用[...]

一步一步,这就是:

audio = AudioInput()        # creates an empty queue
audio.run()                 # adds a value to the queue
interpretor = Interpretor() # implicit call to Queue.__init__ resets queue
interpretor.run()           # queue is empty, call blocks

使用__new__实现单例时,这是一个常见问题。您可以通过使用元类或使用不同的函数来获取队列单例来解决此问题:

class QueueAudio(Queue):
    @classmethod
    def new(cls):
        if '_inst' not in vars(cls):
            cls._inst = cls()
            print('Creating {}'.format(cls.__name__))
        return cls._inst

# create a queue instance with "QueueAudio.new()"

答案 2 :(得分:0)

嗨,您可以按照本例实现单例队列

创建一个单例装饰器

# singleton.py
def singleton(class_):
     instances = {}

     def getinstance(*args, **kwargs):
         if class_ not in instances:
             instances[class_] = class_(*args, **kwargs)
         return instances[class_]

     return getinstance

知道用单例装饰定义您的队列类

 #singleton_queue.py
 import singleton.py
 import queue


 @singleton
 class MySingletonQueue:

      def __init__(self, **kwargs):
           self.q = queue.Queue()

      def put(self, data):
           self.q.put(data)
      ...

我希望对您有帮助