对象池设计模式的Python实现

Odd*_*ing 19 python design-patterns data-structures

我需要一个对象池,而不是自己实现它,我想我会四处寻找一个现成的和经过测试的Python库.

我发现很多其他人在寻找,但没有得到很多直接的答案,所以我把它带到了Stack Overflow.

在我的例子中,我有大量的线程(使用threading模块),需要偶尔调用一个基于SOAP的远程服务器.他们每个人都可以建立自己与服务器的连接,但设置套接字并完成身份验证过程是很昂贵的(它受到服务器的限制),所以我想共享一个连接池,只在需要时创建更多连接.

如果要汇总的项目是工作子过程,我可能已经选择了multiprocessing.pool,但它们不是.如果它们是工作线程,我可能选择了这个实现,但它们不是.

如果它们是MySQL连接,我可能选择了pysqlpool,但它们不是.同样,SQLAlchemy Pool已经出局了.

如果有一个线程,使用可变数量的连接/对象,我会考虑这个实现,但我需要它是线程安全的.

我知道我可以很快再次实现它,但鉴于有很多人在寻找它,我认为Stack Overflow上的规范答案会很好.

Ale*_*lli 25

在我的描述中,在我看来,你需要的是一个连接池,而不是对象.为了简单的线程安全,只需将可重用连接保留在Queue.Queue实例中,然后调用它pool.当一个线程实例化一个连接包装对象时,该对象通过pool.get()它自动获取它的连接(如果当前没有可用的连接则自动将它排队等待,并在连接准备就绪时将其出列); 当对象使用其连接完成时,它会将其放回池中pool.put.

除了Queue.Queue已经提供的内容之外,这里几乎没有普遍要求的通用功能,没有任何提供它的模块是众所周知的或流行的并不奇怪 - 当它有大约6行功能代码时很难使模块普及总之(例如,调用用户提供的连接工厂以提前填充队列或准时填充到某个最大数量 - 通常不是一个很大的附加值)."厚胶",从标准库模块厚厚地包裹底层功能而没有实质性的附加值,毕竟是体系结构减去;-).

  • @Oddthinking,是的,Python标准库中的`Queue`模块就是这样 - 一个线程安全队列(基本的是LIFO,还有优先级和FIFO变体).至于"汇集什么",我的观点是:游泳池连接尽可能轻微包裹或打开,因为连接是昂贵的部分; 将一个当前未使用的连接包装在一个全新的包装对象中,为一个事务的持续时间添加所需的所有修剪应该比较便宜和快速,因此,不需要集合包装器! (2认同)

Dav*_*vid 6

我有一个类似的问题,我必须说 Queue.Queue 非常好,但是有一个拼图的缺失部分。以下类有助于确保获取的对象返回到池中。包括示例。

我允许通过 2 种方式使用此类,即使用关键字或使用析构函数封装对象。with 关键字是首选,但如果您由于某种原因不能/不想使用它(最常见的是需要来自多个队列的多个对象),至少您有一个选择。如果您选择使用该方法,则有关不会调用析构函数的标准免责声明适用。

希望这可以帮助与 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
  '''
Run Code Online (Sandbox Code Playgroud)