Реализация Python шаблона проектирования пула объектов - PullRequest
19 голосов
/ 03 октября 2009

Мне нужен объектный пул , и вместо того, чтобы реализовывать его самостоятельно, я подумал, что поищу готовую и протестированную библиотеку Python.

Я нашел множество других людей , которые смотрели , но не получили много прямых ответов, поэтому я перенес это сюда, в Переполнение стека.

В моем случае у меня большое количество потоков (использующих модуль threading), которым необходимо время от времени вызывать удаленный сервер на основе SOAP. Каждый из них может установить свое собственное соединение с сервером, но настройка сокета и завершение процесса аутентификации обходится дорого (он ограничивается сервером), поэтому я хочу совместно использовать пул соединений, создавая больше только по мере необходимости.

Если бы элементы для пула были рабочими подпроцессами, я мог бы выбрать multiprocessing.pool, но это не так. Если бы они были рабочими потоками, я бы выбрал эту реализацию , но это не так.

Если бы это были соединения MySQL, я бы выбрал pysqlpool , но это не так. Точно так же SQLAlchemy Pool отсутствует.

Если бы существовал один поток, использующий переменное число соединений / объектов, я бы рассмотрел эту реализацию , но мне нужно, чтобы она была поточно-ориентированной.

Я знаю, что мог бы реализовать это снова довольно быстро, но, учитывая, что многие ищут его, я подумал, что канонический ответ о переполнении стека будет хорошим.

Ответы [ 2 ]

24 голосов
/ 03 октября 2009

Из вашего описания мне кажется, что вам нужен пул соединений , а не объектов. Для обеспечения безопасности потоков просто сохраните повторно используемые подключения в экземпляре Queue.Queue, назовите его pool. Когда поток создает экземпляр объекта, обертывающего соединение, объект получает свое соединение через pool.get() (который автоматически ставит его в очередь на ожидание, если в данный момент нет доступных соединений, и удаляет его из очереди, когда соединение готово к нему); когда объект завершает использование своего соединения, он помещает его обратно в пул через pool.put.

В этом так мало универсально необходимой универсальной функциональности, помимо того, что уже дает Queue.Queue, поэтому неудивительно, что нет модуля, если он хорошо известен или популярен - трудно сделать модуль широко распространенным, когда он имеет всего около 6 строк функционального кода (например, для вызова фабрики соединений, предоставленной пользователем, для заполнения очереди либо заранее, либо точно в срок до некоторого максимального числа - в общем, в общем, небольшая добавленная стоимость). «Толстый клей», плотно упаковывающий базовую функциональность стандартного библиотечного модуля без существенной добавленной стоимости, в конце концов, является архитектурным минусом; -).

4 голосов
/ 16 февраля 2011

У меня была похожая проблема, и я должен сказать, что Queue.Queue довольно хорошая, однако в ней есть недостающий фрагмент головоломки. Следующий класс помогает разобраться с тем, что полученный объект возвращается в пул. Пример включен.

Я позволил использовать этот класс двумя способами: с помощью ключевого слова или инкапсуляции объекта с деструктором. Ключевое слово with является предпочтительным, но если вы не можете / не хотите использовать его по какой-либо причине (наиболее распространенной является необходимость использования нескольких объектов из нескольких очередей), по крайней мере, у вас есть опция. Стандартные заявления об отказе от вызова деструктора применяются, если вы решите использовать этот метод.

Надеется, что это поможет кому-то с той же проблемой, что и ОП и я.

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
  '''
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...