Python Реализация шаблона проектирования пула объектов
Мне нужен Пул объектов, и вместо того, чтобы реализовывать его сам, я подумал, что буду искать готовую и протестированную библиотеку Python.
То, что я нашел, было много других людей глядя, но не получало много прямых ответов, поэтому я привел его сюда в Stack Overflow.
В моем случае у меня есть большое количество потоков (с использованием модуля threading
), которые иногда нужно вызывать на удаленном сервере на основе SOAP. Они могут каждый установить свое собственное соединение с сервером, но настройка сокета и завершение процесса аутентификации дорогостоящая (она затухает от сервера), поэтому я хочу разделить пул соединений, создавая больше только по мере необходимости.
Если элементы для пула являются рабочими подпроцессами, я мог бы выбрать multiprocessing.pool
, но это не так. Если бы они были рабочими потоками, я мог бы выбрать эту реализацию, но это не так.
Если они были соединениями MySQL, я мог бы выбрать pysqlpool, но это не так. Аналогичным образом отсутствует SQLAlchemy Pool.
Если бы существовал один поток, используя переменное число соединений/объектов, я бы рассмотрел эту реализацию, но мне нужно, чтобы это был поток -safe.
Я знаю, что могу реализовать это снова довольно быстро, но, учитывая, что многие ищут его, я думал, что канонический ответ на Qaru будет приятным.
Ответы
Ответ 1
Мне кажется, из вашего описания, что вам нужен пул соединений, а не объектов. Для простой защиты потоков просто держите повторно используемые соединения в экземпляре Queue.Queue
, назовите его pool
. Когда поток создает экземпляр объекта, связанного с соединением, объект получает свое соединение через pool.get()
(который автоматически останавливает его, чтобы ждать, если в настоящее время нет доступных соединений и удаляет его, когда соединение готово к нему); когда объект выполнен с использованием своего соединения, он возвращает его в пул через pool.put
.
Там так мало универсально требуемой универсальной функциональности в этом, помимо того, что уже дает вам Queue.Queue
, что неудивительно, что модуль, который является общеизвестным или популярным, трудно распространять, когда он имеет всего около 6 строк функционального кода (например, для вызова пользовательского соединения factory для заполнения очереди либо заранее, либо точно в срок до некоторого максимального числа, но в любом случае это не большое добавленное значение). "Толстый клей", густо обертывающий базовую функциональность из стандартного библиотечного модуля без существенной добавленной стоимости, в конце концов, является архитектурным минусом; -).
Ответ 2
У меня была аналогичная проблема, и я должен сказать, что Queue.Queue неплохо, однако есть недостающая часть головоломки. Следующий класс помогает справиться с тем, что полученный объект возвращается в пул. Пример включен.
Я разрешил использовать два способа использования этого класса с ключевым словом или инкапсулирующим объектом с деструктором. Ключевое слово "с" предпочтительнее, но если вы не можете/не хотите использовать его по какой-либо причине (чаще всего это необходимость в нескольких объектах из нескольких очередей), по крайней мере, у вас есть опция. Если вы решите использовать этот метод, будут применяться стандартные отказы о деструкторе, которые не называются.
Надеется, что это поможет кому-то с той же проблемой, что и OP и я.
class qObj():
_q = None
o = None
def __init__(self, dQ, autoGet = False):
self._q = dQ
if autoGet == True:
self.o = self._q.get()
def __enter__(self):
if self.o == None:
self.o = self._q.get()
return self.o
else:
return self.o
def __exit__(self, type, value, traceback):
if self.o != None:
self._q.put(self.o)
self.o = None
def __del__(self):
if self.o != None:
self._q.put(self.o)
self.o = None
if __name__ == "__main__":
import Queue
def testObj(Q):
someObj = qObj(Q, True)
print 'Inside func: {0}'.format(someObj.o)
aQ = Queue.Queue()
aQ.put("yam")
with qObj(aQ) as obj:
print "Inside with: {0}".format(obj)
print 'Outside with: {0}'.format(aQ.get())
aQ.put("sam")
testObj(aQ)
print 'Outside func: {0}'.format(aQ.get())
'''
Expected Output:
Inside with: yam
Outside with: yam
Inside func: sam
Outside func: sam
'''