Reputation: 157
I'm creating a bunch of components in my project, each of them will be running in different threads.
They will communicate through queue.Queue
. I would like to define all the different queues, which is classes that extends queue.Queue
. Each of them will be singleton object, so the different components can just import that class, and get the instance.
I put everything in one file:
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()
In the constructor of the two components (AudioInput
and Interpretor
) I print the object, to make sure they are the same.
AudioInput
put a string in the queue, and Interpretor
reads it. However, the queue in Interpretor
is always empty, making the program hangs forever.
Here's the output of the program:
Creating QueueAudio
<__main__.QueueAudio object at 0x103234c18>
<__main__.QueueAudio object at 0x103234c18>
Upvotes: 1
Views: 1712
Reputation: 560
hi you can implement your singleton queue as this example
create a singleton decorator
# 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
know define your queue class with singleton decoration
#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)
...
i hope that is helpful
Upvotes: 0
Reputation: 43316
What's happening here is that after your __new__
function returns the queue object, python implicitly calls __init__
on it. This resets the queue and any items you've previously added are removed.
From the docs on __new__
:
If
__new__()
returns an instance of cls, then the new instance’s__init__()
method will be invoked [...]
Step by step, this is what happens:
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
This is a common problem when implementing singletons with __new__
. You can work around this by using a metaclass, or by using a different function to get the queue singleton:
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()"
Upvotes: 2
Reputation: 157
I solve my problem by using another method to define my class as a singleton :
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
Upvotes: 2