Подтвердить что ты не робот

Python Реализация шаблона проектирования пула объектов

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

То, что я нашел, было много других людей глядя, но не получало много прямых ответов, поэтому я привел его сюда в Stack Overflow.

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

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

Если они были соединениями MySQL, я мог бы выбрать pysqlpool, но это не так. Аналогичным образом отсутствует SQLAlchemy Pool.

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

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

4b9b3361

Ответ 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
  '''