Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/design-patterns/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/loops/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
对象池设计模式的Python实现_Python_Design Patterns_Data Structures - Fatal编程技术网

对象池设计模式的Python实现

对象池设计模式的Python实现,python,design-patterns,data-structures,Python,Design Patterns,Data Structures,我需要一个Python库,而不是自己实现它,我想我应该四处寻找一个现成的、经过测试的Python库 我发现有很多其他人,但没有得到很多直接的答案,所以我把它带到这里来 在我的例子中,我有大量线程(使用线程模块),它们偶尔需要调用远程基于SOAP的服务器。他们每个人都可以建立自己与服务器的连接,但设置套接字和完成身份验证过程的成本很高(这是由服务器限制的),因此我想共享一个连接池,仅在需要时创建更多连接 如果池中的项目是工作者子进程,我可能选择了多处理.pool,但它们不是。如果它们是工作线程,我

我需要一个Python库,而不是自己实现它,我想我应该四处寻找一个现成的、经过测试的Python库

我发现有很多其他人,但没有得到很多直接的答案,所以我把它带到这里来

在我的例子中,我有大量线程(使用
线程
模块),它们偶尔需要调用远程基于SOAP的服务器。他们每个人都可以建立自己与服务器的连接,但设置套接字和完成身份验证过程的成本很高(这是由服务器限制的),因此我想共享一个连接池,仅在需要时创建更多连接

如果池中的项目是工作者子进程,我可能选择了
多处理.pool
,但它们不是。如果它们是工作线程,我可能会选择,但它们不是

如果它们是MySQL连接,我可能会选择,但它们不是。类似地,这项计划也被取消了

如果有一个线程,使用可变数量的连接/对象,我会考虑,但我需要它是线程安全的。< /P>


我知道我可以很快地再次实现它,但考虑到有很多人在寻找它,我认为一个关于堆栈溢出的规范答案会很好。

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


除了Queue.Queue已经提供给您的功能之外,这里面几乎没有什么通用的功能,所以没有模块是不足为奇的,只要它是众所周知的或流行的——当一个模块总共有大约6行功能代码时,很难让它广为使用(例如,调用用户提供的连接工厂,提前或及时填充队列,直到达到某个最大值——无论如何,一般来说,这不是一个大的附加值)。“厚胶”,从标准库模块中厚包装底层功能,而没有实质性的附加值,毕竟是一个架构上的缺点;-).

我有一个类似的问题,我必须说排队。排队很好,但有一块拼图缺失了。下面的类有助于确保获取的对象返回池。包括一个例子

我允许使用这个类的两种方法,使用关键字或使用析构函数封装对象。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
  '''

对于简单用例,以下是基于列表的对象池模式的示例实现:

资料来源:


啊,对了,等着吧,如果池子里没有别的了,那就是名单上缺少的。我以为我很聪明,用列表代替队列,但实际上我太聪明了。:)@Lennart,也不能保证线程安全,根据实现的不同,您可能会遇到问题,也可能不会遇到问题——使用Queue.Queue,您的线程安全是有保证的。Python已经内置了线程安全队列了吗?我不知道!是的,这将加快实现速度(我认为这会很短,但主要花在思考并发性问题上)。抱歉,我不理解您关于“连接池”和“对象池”的区别。我说过我想“共享一个连接池”,但这些连接中的每一个都封装在一个对象中,所以它实际上也是一个对象池。不过,我试图区分的是,连接对象不是活动的(与multiprocessing.pool不同)。@oddsthinking,是的,Python标准库中的
队列
模块正是一个线程安全队列(基本队列是LIFO,也有优先级和FIFO变体)。至于“什么是池”,我的观点是:池连接尽可能轻装或拆开,因为建立连接是昂贵的部分;将当前未使用的连接包装在一个全新的包装对象中,该包装对象可以为一个事务的持续时间添加所需的所有修剪,相比之下,该包装应该既便宜又快速,因此,无需将包装合并在一起!IMHO唯一缺少的是
\uu getattr\uu
方法,因此您可以将其视为封装对象的包装器,考虑到Python队列,而不是可重用池中的列表,因为它被宣传为线程安全的。我不确定Python列表是否在所有实现上。
"""
Offer a significant performance boost; it is most effective in
situations where the cost of initializing a class instance is high, the
rate of instantiation of a class is high, and the number of
instantiations in use at any one time is low.
"""


class ReusablePool:
    """
    Manage Reusable objects for use by Client objects.
    """

    def __init__(self, size):
        self._reusables = [Reusable() for _ in range(size)]

    def acquire(self):
        return self._reusables.pop()

    def release(self, reusable):
        self._reusables.append(reusable)


class Reusable:
    """
    Collaborate with other objects for a limited amount of time, then
    they are no longer needed for that collaboration.
    """

    pass


def main():
    reusable_pool = ReusablePool(10)
    reusable = reusable_pool.acquire()
    reusable_pool.release(reusable)


if __name__ == "__main__":
    main()